/* find first matching file and find next matching file
** written by Peter Wu @ Faculty Support Center @ Univ. of Wisconsin
** July 1986
**
** These functions have an extended capability to search for
** directories only and ffmf does not return "." and "..", also
** ffmf will attempt to find root directory and return at least drive number
*/
#define LINT_ARGS

#include "dta.h"
#include <dos.h>
#include <stdlib.h>

char lastc(char *);

ffmf(fn,attr,dta)  /* extended version of ffmf1; fn must be normalized */
char *fn;
short attr;
union dtbuf *dta;
{
  int status, len;
  char tmpfn[200];
  union dtbuf tmpdta;

  if (lastc(fn) != '\\') {  /* if not looking for root directory */

    status = ffmf1(fn,attr,dta);
    if (status) {
      return status;
    }

    /* get rid of "." and ".." */
    while (dta->dos.fn[0] == '.') {
      status = fnmf1(dta);
      if (status) {
	return status;
      }
    }

    /* now check to see if we should return plain files or not */
    while ( ((dta->dos.e_attr & A_FIL) == 0) &&
	    ((dta->dos.attr & A_DIR) == 0) ) {
      /* user didn't ask for plain files and we found one, so skip it */
      status = fnmf1(dta);
      if (status) {
	return status;
      }
    }

    fixdta(dta,dta);
    return 0;
  }

  /* fn ends with '\', i.e. looking for root directory. In DOS 3 ffmf1 won't
  ** find root directory, and in DOS 2 ffmf1 found root directory but reports
  ** it to have file status! Neither is right. So I have to fix it here.
  ** The reason for wanting to look for a root directory is to find out
  ** what drive it's on.
  */

  if (attr & A_DIR) {
    /* look for '\*.*' */
    strcpy(tmpfn, fn);
    strcat(tmpfn, "*.*");
    status = ffmf1(tmpfn, A_DIR | A_FIL, &tmpdta);
    if (status) {  /* can't even find root this way: root must be empty */
      cputs("empty root directory; nothing to move\n\015");
      exit(1);
    }

    /* found root; now fill in dta */
    dta->dos.fn[0] = '\0';
    dta->dos.attr = A_DIR;
    fixdta(&tmpdta,dta);
    return 0;
  } else {
    return 1; /* can't find root because attr is not set to A_DIR */
  }
}

/* extended version of fnmf1; because of the way ffmf handle root directory,
** calling ffmf to find root directory and then call fnmf will cause an
** "allocation table bad" error
*/
fnmf(dta)
union dtbuf *dta;
{
  int status;

  status = fnmf1(dta);
  if (status) {
    return status;
  }

  while (((dta->dos.e_attr & A_FIL) == 0) && ((dta->dos.attr & A_DIR) == 0)) {	   /* user didn't ask for plain file and we found one, so skip it */
    status = fnmf1(dta);
    if (status) {
      return status;
    }
  }

  fixdta(dta,dta);
  return 0;  /* no error */
}

/* copy dos dependent dta fields to the dos independent dta fields */
fixdta(from, to)
union dtbuf *from, *to;
{
  switch (_osmajor) {

    case 3:  /* dos 3.xx */
      to->dos.drv_no = from->dos3.drv_no;
      to->dos.slotl = from->dos3.slotl;
      to->dos.sloth = from->dos3.sloth;
      to->dos.clusl = from->dos3.clusl;
      to->dos.clush = from->dos3.clush;

      to->dos3.drv_no = from->dos3.drv_no;  /* for compatiblity sake */
      break;

    case 2:  /* dos 2.xx */
      to->dos.drv_no = from->dos2.drv_no + 1;
      to->dos.slotl = from->dos2.slotl;
      to->dos.sloth = from->dos2.sloth;
      to->dos.clusl = from->dos2.clusl;
      to->dos.clush = from->dos2.clush;

      to->dos2.drv_no = from->dos2.drv_no;  /* for compatiblity sake */
      break;

    default:
      cputs("unexpected DOS version\n\015");
      error("fixdta", 0);
  }
}

ffmf1(fn,attr,dta)  /* don't call this, call ffmf */
char *fn;
short attr;
union dtbuf *dta;
{
  union REGS inregs,outregs;

  dta->dos.e_attr = attr;  /* store the extended attribute */
  bdos(0x1a, (int) dta, 0);  /* set dta */

  inregs.h.ah = 0x4e;
  inregs.x.dx = (int) fn;
  inregs.x.cx = attr & 0x3f;  /* mask off the A_FIL bit */
  intdos(&inregs, &outregs);  /* now find first entry */

  if (outregs.x.cflag) {
    return outregs.x.ax;  /* return error code */
  }
  return 0;  /* no error */
}

fnmf1(dta)  /* find next matching file */
union dtbuf *dta;
{
  union REGS inregs,outregs;

  bdos(0x1a, (int) dta, 0);  /* set dta */

  inregs.h.ah = 0x4f;
  intdos(&inregs, &outregs);  /* now find next entry */

  if (outregs.x.cflag) {
    return (outregs.x.ax);
  } else {
    return (0);
  };
}
