/*	filewdir.c	CI-C86 Utility Function

	Copyright (c) 1985 by:

		Lawrence R. Steeger
		1009 North Jackson Street
		Milwaukee, Wisconsin 53202
		414-277-8149
*/

#include <stdio.h>

typedef	struct _files {

		struct _files *_fchain,	/* next FILES pointer */
			      *_bchain;	/* previous FILES pointer */

		unsigned int _fmode;	/* original "mode" */

		unsigned char *_fspec,	/* original "filespec" */
			      *_file1,	/* 1st file name */
			      *_fnext;	/* next file name */
	} FILES;

#define	fchain fcurr->_fchain
#define bchain fcurr->_bchain
#define fmode fcurr->_fmode
#define	fspec fcurr->_fspec
#define	file1 fcurr->_file1
#define	fnext fcurr->_fnext

static	FILES *fanchor = NULL;		/* FILES anchor pointer */

/*	filewdir(filespec,mode)

	Return file name specifications that match a wildcard "filespec"
	in the specified "mode".

	Returns:  (unsigned char *)	1st or next file name specification
		  NULL			no more file name specifications

	Note:	  File name specifications returned may be freed
		  by using free().

		  To reset all file specifications in progress
		  use "filewdir("")".  Any currently active
		  "filespec"s will be purged.

		  Legal file modes are:

			0x00	Normal
			0x01	Read Only
			0x02	Hidden
			0x04	System
			0x08	Volume Label
			0x10	Subdirectory
			0x20	Archive
*/

unsigned char *filewdir(filespec, mode)
unsigned char *filespec;
unsigned int mode;
{
	unsigned char *filedir();	/* standard CI-C86 "dir" function */

	char *alloc(),			/* standard function */
	     *strcpy();			/* standard function */

	register FILES *fcurr,		/* FILES current entry pointer */
		       *ftemp;		/* FILES temporary pointer */

	unsigned char *fileptr;		/* file name specification pointer */

	if (*filespec == '\0') {	/* purge all FILES */

		for (fcurr = fanchor; fcurr != NULL;) {	/* run FILES chain */

			ftemp = fchain;

			/* free a FILES entry */

			free(fspec);
			free(file1);
			free((unsigned char *)fcurr);

			fcurr = ftemp;
		}

		return (unsigned char *)(fanchor = NULL);
	}

	/*	search FILES for matching file specification and file mode */

	for (fcurr = ftemp = fanchor;
	     fcurr != NULL;
	     ftemp = fcurr, fcurr = fchain)

		if ((strcmp(fspec, filespec) == 0)
		&&  (mode == fmode))
			break;

	if (fcurr != NULL) {		/* existing entry found... */

		if (*fnext) {		/* ...and a file name exists */

			fileptr = alloc((strlen(fnext) + 1));	/* file name */
			strcpy(fileptr, fnext);

			fnext += (strlen(fnext) + 1);	/* next file name */

			return (fileptr);		/* return file name */
		}

		/* no more file names - dechain this entry and return NULL */

		if (bchain == NULL)
			fanchor = fchain;		/* 1st on chain */
		else
			bchain->_fchain = fchain;	/* not 1st on chain */

		/* free this entry */

		free(fspec);
		free(file1);
		free((unsigned char *)fcurr);

		return (NULL);			/* indicate no files left */
	}

	/*	new FILES entry may be required	*/

	if (*(fileptr = filedir(filespec, mode)) == '\0') {
		free(fileptr);
		return (NULL);			/* no file names */
	}

	/*	at least 1 file name found	*/

	fcurr = alloc(sizeof(FILES));		/* allocate FILES entry */

	if (ftemp == NULL)
		fanchor = fcurr;		/* 1st on chain */
	else
		ftemp->_fchain = fcurr;		/* last on chain */

	bchain = ftemp;				/* back chain link */

	fspec = alloc(strlen(filespec) + 1);	/* save file specification */
	strcpy(fspec, filespec);

	fmode = mode;				/* save file mode */

	file1 = fnext = fileptr;		/* set files' pointers */

	fileptr = alloc((strlen(fileptr) + 1));	/* get file name storage */
	strcpy(fileptr, fnext);

	fnext += (strlen(fnext) + 1);		/* next file name pointer */

	return (fileptr);			/* return 1st file name */
}

/*	get file directory

	note:

	this contains a bypass for the way DOS functions 0x4e and 0x4f
	work.  this bypass enables true selection by mode.

	an extension has been added to "mode".  if mode = 0xffff then
	all file names matching the filespec will be returned.
*/

unsigned char *realloc(); 

struct ff_str {
  char dummy[21];		/* reserved for dos */ 
  unsigned char attribute;	/* returned attribute */ 
  unsigned time; 
  unsigned date; 
  long size;			/* size of file */ 
  unsigned char fn[13];		/* string containing the filename */ 
};

unsigned char *filedir(filename,mode)
unsigned char *filename;
unsigned mode;
{
  struct {int ax,bx,cx,dx,si,di,ds,es;}srv;
  struct ff_str ff_area;
  unsigned char *result=0;
  int reslen=0; 

#ifdef _C86_BIG 
  srv.ds=((unsigned long)filename)>>16; 
#else 
  segread(&srv.si);		/* get ds value */
#endif 
  srv.dx=filename;
  if (mode) srv.cx=0xff;		/* set search all modes */
  else srv.cx=0x00;			/* set search normal only */
  bdos(0x1a,&ff_area);			/* set the transfer address */
  for(srv.ax=0x4e00;!(sysint21(&srv,&srv)&1);srv.ax=0x4f00){
/*    printf(":%s 0x%02x:", ff_area.fn, ff_area.attribute); */
    if ((mode && !(ff_area.attribute & (unsigned char)mode))
    &&  (mode != 0xffff)) {
/*	printf("\n"); */
	continue;
    }
    /* return only filenames with desired modes */
    result=realloc(result,reslen+strlen(ff_area.fn)+1);
    if (result==NULL) return NULL;	/* no memory left */
    strcpy(result+reslen,ff_area.fn);
    reslen+=strlen(ff_area.fn)+1;
/*    printf("<\n"); */
  } 
  return realloc(result,reslen+1); 
}

/*	end of filewdir.c	*/

 