#include "all03.h"

char path[260], oldpath[260];

word Chks = 0x0000;
unsigned char huge *buffer = NULL;
char buffile[80] = "C:\\BUFF.TMP";

long BufStart= 0x00000000L;
long BufEnd  = 0x00FFFFFFL;
long bufsize = 0x01000000L;

static struct fatr {
	char fname[13];
	long fsize;
	char fattr;
	struct {
		unsigned day:5;
		unsigned month:4;
		unsigned year:7;
	} fdate;
} f[1000];
static char filename[260];
static char fmatch[15] = "*.*";

int xgets( char *str )
{
	struct text_info ti;
	int i;

	gettextinfo( &ti );

	str[1] = str[2] = 0;

	for( ;; )
	{
		gotoxy( ti.curx, ti.cury );
		cprintf( str+2 ); cprintf( " " );
		gotoxy( ti.curx+str[1], ti.cury );

		switch( i = getch() )
		{
		case 0:
			getch();
			break;

		case 0x09:
			str[1] = str[2] = 0;
			return 0;

		case 0x1B:
			str[1] = str[2] = 0;
			return -1;

		case 0x08:
			if( str[1] )
				str[ 2 + --str[1] ] = 0;
			break;

		case '\n':
		case '\r':
			return 1;

		default:
			str[ 2 + str[1]++ ] = i;
			str[ 2 + str[1] ] = 0;
			break;
		}
	}
}

unsigned long read_bin( char *filename, unsigned long addr )
{
	FILE *f, *o = NULL;
	int i;

	Chks = 0;

	if( ( f = fopen( filename, "rb" ) ) == NULL )
		return -1;

	if( !buffer && ( o = fopen( buffile, "wb" ) ) == NULL )
		return -1;

	while( ( i = getc( f ) ) != EOF && addr < bufsize )
	{
		if( !buffer ) putc( i, o );
		else buffer[addr] = i;

		Chks += i;
		++addr;
	}

	if( o ) fclose( o );
	fclose( f );
	return addr-1;
}

static char *pos;

static unsigned char getval( void )
{
	unsigned char c1, c2;

	c1 = toupper( *pos++ );
	c2 = toupper( *pos++ );

	c1 = ( (c1 > '9') ? c1 - 'A'+10 : c1 - '0' );
	c2 = ( (c2 > '9') ? c2 - 'A'+10 : c2 - '0' );

	return ( c1 << 4 ) | c2;
}

unsigned long read_intel( char *filename, unsigned long addr )
{
	FILE *f, *o = NULL;
	char l[160];
	unsigned a;
	unsigned char d, chk, num;

	addr = 0;
	Chks = 0;

	if( ( f = fopen( filename, "r" ) ) == NULL )
		return -1;

	if( !buffer && ( o = fopen( buffile, "wb" ) ) == NULL )
		return -1;

	while( ( pos = fgets( l, 160, f ) ) != NULL )
	{
		if( *pos++ != ':' )
			continue;

		chk  = ( num = getval() );				// num bytes
		chk += ( d = getval() ); a = 256 * d;	// address high
		chk += ( d = getval() ); a |= d;		// address low
		chk += getval();						// type

		while( num-- )
		{
			chk += ( d = getval() );
			if( a < bufsize )
			{
				Chks += d;
				if( !buffer ) putc( d, o );
				else buffer[a] = d;
				++a;
			}
		}
		if( ( ( chk + getval() ) & 0xFF ) != 0 )
		{
			errbeep();
			if( o ) fclose( o );
			fclose( f );
			return 0L;
		}
		if( a > addr )
			addr = a;
	}

	if( o ) fclose( o );
	fclose( f );
	return addr-1;
}

unsigned long read_motorola( char *filename, unsigned long addr )
{
	*filename = 0;
	delay(2000);
	return addr+100;
}

static int cmp( const void *fl1, const void *fl2 )
{
	struct fatr *f1 = (struct fatr *)fl1;
	struct fatr *f2 = (struct fatr *)fl2;

	if( f1->fattr != f2->fattr )	return f1->fattr - f2->fattr;
	else							return strcmp( f1->fname, f2->fname );
}

int load_file( void )
{
	int i, done, left, top, newpath, numfiles, pos;
	unsigned long addr;
	char tmp[33], *cptr;

	textattr( ( LIGHTGRAY << 4 ) | YELLOW ); clscrn( 0,0, 24,39 );

	textattr( ( CYAN << 4 ) | WHITE );
	_window( 0,0, 22,39 );					// left
	_window( 2,1, 16,7 );					// drives
	locate( 13, 41 ); cprintf( "File name: " );

	textattr( ( BLUE << 4 ) + WHITE );
	locate( 11, 41); cprintf( "  LOAD :" );

More:
	textattr( ( CYAN << 4 ) | WHITE );
	_window( 12,40, 22,79 );				// right
	locate( 13, 41 ); cprintf( "File name: " );
	filename[0] = 0;

	newpath = 1;
	left = 0;

	for( done = 0; !done; )
	{
		textattr( ( LIGHTGRAY << 4 ) | YELLOW ); clscrn( 23,0, 23,79 );
		textattr( ( BLUE << 4 ) + WHITE );
		locate( 23, 0 );
		if( left )
			cprintf( "Command:Tab PgUp PgDn Up Home End Esc Enter Drive-letter F1:files" );
		else
			cprintf( "Command:Tab Esc Enter" );

		textattr( ( CYAN << 4 ) | WHITE );
		if( left ) dbl = 1; frame( 0,0, 22,39 );
		dbl ^= 1; frame( 12,40, 22,79 );
		dbl = 0;

		if( newpath )
		{
			struct ffblk ff;
			char fname[260];

			newpath = numfiles = 0;

			for( i = 0; i < 13; ++i )
			{
				if( path[0] == 'A'+i )
					textattr( ( BLUE << 4 ) + WHITE );
				else
					textattr( ( CYAN << 4 ) | WHITE );
				locate( 3+i, 2 ); cprintf( "%c:", 'A'+i );

				if( path[0] == 'N'+i )
					textattr( ( BLUE << 4 ) + WHITE );
				else
					textattr( ( CYAN << 4 ) | WHITE );
				locate( 3+i, 5 ); cprintf( "%c:", 'N'+i );
			}
			textattr( ( CYAN << 4 ) | WHITE );

			strcpy( fname, path );
			strcat( fname, "\\*.*" );

			done = findfirst( fname, &ff, 0xFFFF );
			while( !done && numfiles < 1000 )
			{
				if( ( ff.ff_attrib & FA_DIREC ) != 0 &&
					!( ff.ff_name[0] == '.' && ff.ff_name[1] == 0 ) )
				{
					strcpy( f[numfiles].fname, ff.ff_name );
					f[numfiles].fattr = FA_DIREC;
					*(unsigned*)&f[numfiles].fdate = ff.ff_fdate;
					f[numfiles++].fsize = 0;
				}
				done = findnext( &ff );
			}

			strcpy( fname, path );
			strcat( fname, "\\" );
			strcat( fname, fmatch );

			done = findfirst( fname, &ff, 0xFFFF );
			while( !done && numfiles < 1000 )
			{
				if( ( ff.ff_attrib & ( FA_LABEL | FA_DIREC ) ) == 0 )
				{
					strcpy( f[numfiles].fname, ff.ff_name );
					f[numfiles].fattr = ff.ff_attrib;
					*(unsigned*)&f[numfiles].fdate = ff.ff_fdate;
					f[numfiles++].fsize = ff.ff_fsize;
				}
				done = findnext( &ff );
			}

			textattr( ( BLUE << 4 ) + WHITE );
			locate( 1, 1 ); cprintf( "%-38.38s", fname );
			textattr( ( CYAN << 4 ) | WHITE );

			qsort( &f, numfiles, sizeof(f[0]), cmp );
			done = pos = top = 0;
		}

		for( i = 0; i < 18; ++i )
		{
			struct fatr *ff = &f[i+top];

			if( i+top == pos )
				textattr( ( BLUE << 4 ) + WHITE );
			else
				textattr( ( CYAN << 4 ) | WHITE );
			locate( i+3, 8 );
			if( i+top < numfiles )
			{
				cprintf( "%-12s ", ff->fname );
				if( ff->fattr & FA_DIREC )
					cprintf( "  <DIR>" );
				else
					cprintf( "%7ld", ff->fsize );
				cprintf( "  %02d-%02d-%02d",
					ff->fdate.month, ff->fdate.day, (ff->fdate.year+80)%100 );
			}
			else
				cprintf( "                              " );
		}

		textattr( ( CYAN << 4 ) | WHITE );
		locate( 13, 52 ); cprintf( "%s ", filename );
		locate( 13, 52+strlen(filename) );

		switch( i = getch() )
		{
			case 0:
				if( !left )
				{
					getch();
					break;
				}

				switch( i = getch() )
				{
				case 59:	// F1
					textattr( ( BLUE << 4 ) + WHITE );
					clscrn( 21, 1, 21, 38 );
					locate( 21, 1 ); cprintf( "Files(%-12s):", fmatch );
					tmp[0] = 0;

					for( done = 0; !done; )
					{
						locate( 21, 21 ); cprintf( "%s ", tmp );
						locate( 21, 21+strlen(tmp) );

						switch( i = getch() )
						{
						case 0:
							getch();
							break;

						case 8:
							if( ( i = strlen( tmp ) ) != 0 )
								tmp[ i-1 ] = 0;
							break;

						case 0x1B:
							done = 1;
							break;

						case '\n':
						case '\r':
							if( ( i = strlen(tmp) ) > 0 && i < 13 )
							{
								strcpy( fmatch, tmp );
								newpath = 1;
							}
							done = 1;
							break;

						default:
							if( strlen( tmp ) < 12 )
								strcat( tmp, (char*)&i );
							break;
						}

					}
					textattr( ( CYAN << 4 ) | WHITE );
					clscrn( 21, 1, 21, 38 );
					done = 0;
					break;

				case 71:	// HOME
					pos = top = 0;
					break;

				case 79:	// END
					if( ( top = numfiles-18 ) < 0 )
						top = 0;
					pos = numfiles - 1;
					break;

				case 72:	// UP
					if( pos )
						--pos;
					if( pos < top )
						top = pos;
					break;

				case 80:	// DOWN
					if( pos+1 < numfiles )
					{
						++pos;
						if( pos >= top+18 )
							++top;
					}
					break;

				case 73:	// PGUP
					if( ( pos -= 9 ) < 0 )
						pos = 0;
					if( pos < top && ( top -= 9 ) < 0 )
						top = 0;
					break;

				case 81:	// PGDN
					if( ( pos += 9 ) >= numfiles )
						pos = numfiles-1;

					if( pos >= top+18 )
					{
						top += 9;
						if( top + 18 >= numfiles )
							top = numfiles - 18;
						if( top < 0 )
							top = 0;
					}
					break;
				}
				break;

			case 8:	// BS
				if( ( i = strlen( filename ) ) > 0 )
					filename[i-1] = 0;
				break;

			case 9:
				left ^= 1; break;

			case 0x1B:
				return 0;

			case '\n':
			case '\r':
				if( !left )
				{
					strcpy( tmp, filename );
					sprintf( filename, "%s\\%s", path, tmp );
					done = 1;
				}
				else if( f[pos].fattr & FA_DIREC )
				{
					if( !strcmp( f[pos].fname, "." ) )
						break;

					newpath = 1;
					if( !strcmp( f[pos].fname, ".." ) )
						*strrchr( path, '\\' ) = 0;
					else
					{
						strcat( path, "\\" );
						strcat( path, f[pos].fname );
					}
				}
				else
				{
					sprintf( filename, "%s\\%s", path, f[pos].fname );
					done = 1;
				}	
				break;

			default:
				if( left )
				{
					if( isalpha( i ) )
					{
						struct ffblk ff;
						char p[260];

						sprintf( p, "%c:\\*.*", toupper(i) );
						if( !findfirst( p, &ff, 0xFFFF ) )
						{
							newpath = 1;
							sprintf( path, "%c:", toupper(i) );
						}
					}
				}
				else if( strlen( filename ) < 12 )
					strcat( filename, (char*)&i );
				break;
		}
	}

	textattr( ( CYAN << 4 ) | WHITE );
	if( ( cptr = strrchr( filename, '\\' ) ) != NULL )
		++cptr;
	else
		cptr = filename;
	locate( 13, 52 ); cprintf( "%s ", cptr );

	locate( 14, 41 ); cprintf( "<B>in,<I>ntel HEX,<M>otorola S HEX : " );
	
	for( done = 0; !done; )
	{
		switch( toupper( getch() ) )
		{
		case 0:		getch(); break;
		case 'B':	i = 'B'; done = 1; break;
		case 'I':	i = 'I'; done = 1; break;
		case 'S':	i = 'S'; done = 1; break;
		case 0x1B:	return 0;
		}
	}

	locate( 15, 41 ); cprintf( "Load address(%05X) : ", addr = BufStart );

	tmp[0] = 6; if( xgets( tmp ) == -1 ) return 0;
	if( tmp[1] )
		addr = atoi( tmp+2 );

	textattr( BLINK | ( LIGHTGREEN << 4 ) | WHITE );
	locate( 16, 41 ); cprintf( "Loading..." );

	switch( i )
	{
	case 'B':	addr = read_bin( filename, addr ); break;
	case 'I':	addr = read_intel( filename, addr ); break;
	case 'S':	addr = read_motorola( filename, addr ); break;
	}

	textattr( ( CYAN << 4 ) | WHITE );
	locate( 16, 41 ); cprintf( "Loaded... " );

	putchar( 7 );
	locate( 17, 41 ); cprintf( "Ok !   END ADDR. : %05X", addr );

	locate( 20, 41 ); cprintf( "Press any key to continue" );
	locate( 21, 41 ); cprintf( "Or press CR to back to menu" );

	switch( getch() )
	{
	case 0:		getch();
	case '\n':
	case '\r':	return 1;
	default  :	goto More;
	}
}

void save_file( void )
{
	char fname[40], tmp[20], done;
	unsigned char v;
	unsigned long i, start = BufStart, ende = BufEnd;
	FILE *f, *o;

	textattr( ( CYAN << 4 ) | WHITE );
	_window( 11,40, 23,79 );

	textattr( ( BLUE << 4 ) + WHITE );
	locate( 11, 41); cprintf( "  SAVE :" );
	
	for( done = 0; !done; )
	{
		textattr( ( CYAN << 4 ) | WHITE ); clscrn( 12,41, 22,78 );

		locate( 12, 41 ); cprintf( "File name: " );
		fname[0] = 30; if( xgets( fname ) != 1 || fname[1] == 0 ) return;

		locate( 13, 41 ); cprintf( "Start address[%05X]:", BufStart );
		tmp[0] = 6; if( xgets( tmp ) != 1 ) return;
		if( tmp[1] ) start = atoi( tmp+2 );

		locate( 14, 41 ); cprintf( "End address[%05X]:", BufEnd );
		tmp[0] = 6; if( xgets( tmp ) != 1 ) return;
		if( tmp[1] ) ende = atoi( tmp+2 );

		if( ( o = fopen( fname+2, "rb" ) ) != NULL )
		{
			fclose( o );

			textattr( ( RED << 4 ) | WHITE );
			locate( 15, 41 ); cprintf( "FILE EXISTS! OVERWRITE(Y/N)? " );
			textattr( ( CYAN << 4 ) | WHITE );

			if( ( done = getch() ) == 0 )
				getch();
			else if( toupper(done) != 'Y' )
			{
				done = 0;
				continue;
			}
			else
			{
				done = 0;
				clscrn( 15,41, 15,78 );
			}
		}

		locate( 15, 41 ); cprintf( "Saving now..." );

		locate( 16, 41 );
		if( ( o = fopen( fname+2, "wb" ) ) == NULL )
		{
			errbeep();
			textattr( ( RED << 4 ) | WHITE ); cprintf( "File open error !" );
			return;
		}

		if( !buffer && ( f = fopen( buffile, "rb" ) ) == NULL )
		{
			errbeep();
			textattr( ( RED << 4 ) | WHITE ); cprintf( "File open error !" );
			return;
		}

		for( i = start; i <= ende; ++i )
		{
			v = ( buffer ? buffer[i] : getc(f) );
			if( putc( v, o ) == EOF )
			{
				errbeep();
				textattr( ( RED << 4 ) | WHITE ); cprintf( "File write error !" );
				fclose( o );
				return;
			}
		}

		fclose( o );
		if( !buffer ) fclose( f );

		putchar( 7 );
		cprintf( " OK !" );

		locate( 20, 41 ); cprintf( "Press any key to continue" );
		locate( 21, 41 ); cprintf( "Or press CR to back to menu " );

		if( ( done = getch() ) == 0 )
			getch();
		else if( ( done = getch() ) == 0x1B || done == '\r' )
			return;
		else
			done = 0;
	}
}


