/*

sectbl.c -- セクタテーブルの処理

*/

#include<stdio.h>
#include<dos.h>
#include<stdlib.h>
#include"dmove86.h"

static	struct SECTBL *rdsec_sub(unsigned long secno)
{
	struct	SECTBL	*p=malloc(sizeof(struct SECTBL));

	static	char	mes_nomem[] = "\aメモリ不足です.";

	if	(p==NULL)
	{
		dm_errmes(mes_nomem);
		return NULL;
	}

	if	((p->buf=farmalloc(Dpb.seclen))==NULL)
	{
		free(p);
		dm_errmes(mes_nomem);
		return NULL;
	}

	p->num = secno;
	p->next = NULL;

	if	(readabssec(p->buf,secno,1,Drive) & 0x100)
	{
		freesectbl(p);
		dm_errmes("\aセクタが読み込めません.");
		return NULL;
	}

	return p;
}

struct DIRENTRY far	**readentry(struct DIRENTRY far *parent,
					struct SECTBL **sectbl,int *dirnum)
{
	struct	SECTBL	dummy;
	struct	SECTBL	*p = &dummy;

	struct DIRENTRY	far **dirtbl;

	unsigned i;
	int	n;
	int	sectornum = 0;

	dummy.next = NULL;

	if	(parent==NULL)	/* ルートディレクトリ */
	{
		for	(i=Dpb.iplsectors+Dpb.fatnum*Fatsize ; 
							i<Dpb.data_sec ; i++)
		{
			p = p->next = rdsec_sub(i);
			if	(p==NULL)
			{
				freesectbl(dummy.next);
				return NULL;
			}
			sectornum++;
		}
	}
	else			/* サブディレクトリ */
	{
		i=parent->cluster;

		do
		{
			unsigned long	s;
			int	j;

			for	(s=CL2SEC(i),j=0 ; j<=Dpb.sec_clu ; j++,s++)
			{
				p = p->next = rdsec_sub(s);

				if	(p==NULL)
				{
					freesectbl(dummy.next);
					return NULL;
				}
				sectornum++;
			}
			i = *(Fat+(unsigned long)i);
		} while (i!=0xffff);
	}

	if	(sectornum == 0)
	{
		dm_errmes("\aディレクトリが全く読み込まれませんでした.");
		return NULL;
	}

	dirtbl = malloc(sizeof(struct DIRENTRY far *)*sectornum*DIRSEC);

	if	(dirtbl == NULL)
	{
		freesectbl(dummy.next);
		dm_errmes("\aメモリ不足です.");
		return NULL;
	}
			/* メモリを解放していないが、これが発生するのは */
			/* ルートの場合のみなので、大丈夫               */
	if	(dummy.next->buf->filename[0]=='\0')
	{
		dm_errmes("\aこのディスクは空です.");
		return NULL;
	}

	n=0;

	for	(p=dummy.next ; p!=NULL ; p=p->next)
	{
		for	(i=0 ; i<DIRSEC ; i++)
		{
			dirtbl[n] = p->buf + i;

			if	(dirtbl[n]->filename[0]=='\0')
				goto end;

			n++;
		}
	}
end:
	*sectbl = dummy.next;
	*dirnum = n;
	return dirtbl;
}

void		freesectbl(struct SECTBL *sectbl)
{
	struct SECTBL	*tblfree;

	while	(sectbl != NULL)
	{
		tblfree = sectbl;
		farfree(tblfree->buf);
		sectbl = tblfree->next;
		free(tblfree);
	}
}

void		writedir(sectbl,dirtbl)
struct SECTBL	*sectbl;
struct DIRENTRY	far **dirtbl;
{
	struct DIRENTRY	far *buftop =
			(struct DIRENTRY far *)farmalloc(Dpb.seclen);
	struct DIRENTRY	far *buf;
	int	i;
	int	f;

	if	(buftop == NULL)
	{
		dm_errmes("\aメモリ不足で書き込めません.");
		goto ENDWRITING;
	}

	for	(f=0 ; sectbl!=NULL && f==0 ; sectbl=sectbl->next)
	{
		buf = buftop;

		for	(i=0 ; i<DIRSEC ; i++,buf++)
		{
			*buf = **(dirtbl++);

			if	(buf->filename[0]=='\0')
			{
				for	( ; i<DIRSEC ; i++)
					(buf++)->filename[0] = '\0';

				f = 1;
				break;
			}
		}

		if	(writeabssec(buftop, sectbl->num, 1, Drive) & 0x100)
		{
			dm_errmes("書き込みエラーです");
			goto ENDWRITING;
		}
	}
ENDWRITING:
	farfree(buftop);
}
