/*

dmove86.c version 1.20c
Copyright (c) 1993 Delmonta

*/

#include<stdio.h>
#include<malloc.h>
#include<dos.h>
#include<ctype.h>
#include<process.h>
#include<signal.h>
#include"dmove86.h"

int		Drive;
unsigned int	Fatsize;
struct DPB	Dpb;
unsigned far	*Fat;

recursive
int		control(parent)
struct DIRENTRY far *parent;
{
	struct DIRENTRY far **dirtbl;

	unsigned int	secnum;	/* そのディレクトリが占めるセクタ数	*/
	unsigned int	dirnum;	/* ディレクトリエントリの数		*/

register unsigned int	i,n;	/* ループカウンターなどの一時変数	*/

	struct SECTBL	sectop;
	struct SECTBL	*sectbl;

REREAD:;
	secnum = 0;
	sectbl = &sectop;

	if	(parent == NULL)	/* ルートディレクトリの場合	*/
	{
		for	(i=Dpb.iplsectors+Fatsize*Dpb.fatnum ;
				i<Dpb.data_sec ; i++)
		{
			struct SECTBL	*up;

			sectbl->next = (struct SECTBL *)malloc
						(sizeof(struct SECTBL));

			if	(sectbl->next == NULL)
				goto ENDROOTDIR;

			up = sectbl;
			sectbl = up->next;

			sectbl->buf = (struct DIRENTRY far *)
					farmalloc(Dpb.seclen);
			if	(sectbl->buf == NULL)
			{
				free(sectbl);
				up->next = NULL;
				goto ENDROOTDIR;
			}

			if	((n=rdabssec(sectbl->buf,i,Drive)) & 0x100)
			{
				dm_errmes("セクタの読み込みに失敗しました");
				farfree(sectbl->buf);
				free(sectbl);
				up->next = NULL;
				goto ENDROOTDIR;
			}

			sectbl->num = i;
			secnum++;
			sectbl->next = NULL;
		}

ENDROOTDIR:;
	}
	else				/* サブディレクトリの場合	*/
	{	unsigned int	cluster = parent->cluster;
		unsigned int	sector;

		do
		{
			sector = CL2SEC(cluster);

			for	(i=0 ; i<=Dpb.sec_clu ; i++)
			{

				struct SECTBL	*up = sectbl;

				up->next = (struct SECTBL *)malloc
						(sizeof(struct SECTBL));

				sectbl = up->next;

				if	(sectbl == NULL)
				{
					goto ENDSUBDIR;
				}
				sectbl->buf = (struct DIRENTRY far *)
						farmalloc(Dpb.seclen);

				if	(sectbl->buf == NULL)
				{
					free(sectbl);
					up->next = NULL;
					goto ENDSUBDIR;
				}

				if	((n=rdabssec(sectbl->buf,
						sector+i,Drive)) & 0x100)
				{
					dm_errmes("セクタの読み込みに失敗しました");
					farfree(sectbl->buf);
					free(sectbl);
					up->next = NULL;
					goto ENDSUBDIR;
				}

				sectbl->num = sector+i;
				sectbl->next = NULL;
				secnum++;
			}
			cluster = *(Fat+(unsigned long)cluster);
		} while	(cluster!=0xffff);
ENDSUBDIR:;
	}

	/* 以降、ルート／サブ共通の処理 */

	if	(secnum == 0)
	{
		dm_errmes("ディレクトリが全く読み込まれませんでした。");
		return 5;
	}

	sectbl = sectop.next;		/* 実はsectopはダミーなのです */

	dirtbl = (struct DIRENTRY far **)malloc(sizeof(struct DIRENTRY far *)
		* secnum * DIRSEC);

	if	(dirtbl == NULL)
	{
		freesectbl(sectop.next);
		dm_errmes("メモリ不足です。");
		return 4;
	}

	if	(sectbl->buf->filename[0]=='\0')
	{
		dm_errmes("このディスクは空です.\n");
		endscreen();
	}

	dirnum = n = 0;

	while(sectbl != NULL)
	{
		for	(i=0 ; i<DIRSEC ; i++)
		{
			dirtbl[n] = sectbl->buf + i;

			if	(dirtbl[n]->filename[0]=='\0' && dirnum==0)
				dirnum = n;

			n++;
		}

		sectbl = sectbl->next;
	}

	if	(dirnum == 0)
		dirnum = secnum*DIRSEC;

	i = 0;
REMENU:;

	i = dmmenu(dirtbl, dirnum, i/4);

	switch (i & 3)
	{
		case UPDIR:
			free(dirtbl);
			freesectbl(sectop.next);
			return 0;

		case CHGDIR:
			control(dirtbl[i/4]);
			break;

		case WRTDIR:
			writedir(sectop.next,dirtbl);
			break;

		case ORIGIN:
			free(dirtbl);
			freesectbl(sectop.next);
			goto REREAD;

	}
	goto REMENU;
}

int	main(argc,argv)
int	argc;
char	*argv[];
{
	if	(argc != 2)
	{	printf("書式 : dmove86 <ドライブ名>\n");
		exit(1);
	}

	Drive = toupper(argv[1][0]) - 'A';

	if	(Drive<0 || Drive>25)
	{	printf("不正なドライブ名です.\n");
		exit(2);
	}

	if	(getdpb() == -1)
	{	printf("指定されたドライブは存在しません.\n");
		exit(2);
	}

	Fat = getfat();

	if	(Fat == NULL)
	{	printf("FATの読み込みに失敗しました.\n");
		exit(3);
	}

	signal(SIGINT,SIG_IGN);

	mkscreen();
	control(NULL);
	endscreen();
}
