

/*		Filecopy Utility Program		*/
/*		MAIN PROGRAM - USER INTERFACE		*/

#include "filecopy.os"
#include "switch.os"
#include "filecopy.inc"

#define	ver	1
#define rev	0
#define mod    'a'
#define asm    'd'
#define date	"March 15, 1984"

/* Change History:

    Last change:     15 March 1984	tpl

	1.0  02/15/84	add file count & deassign drives on abort  - jjc
	0.0j 02/01/84   Read 8 or 9 TPS partitions		   - jjc
	0.0i 01/26/84	Fix up for beta - no IBM format disk reads - jjc    
	0.0h 01/12/84	Use Mike Pampa's assign routine - jjc
	0.0g 01/04/83	Fix user interface & wild card expansion - jjc
	0.0f 11/30/83	Read routines working, start on write routines
	0.0e 11/08/83	Interface to MSDOS read routines
	0.0d 10/30/83	Rewrite, adding interactive interface, get DIR working,
			move definitions into filecopy.inc
	0.0c 10/20/83	Rewrite and test with dummy foreign routines
	0.0b 10/10/83	Split general subroutines into filesubs.c
	0.0a 10/01/83	Initial User Interface coding
*/
/*	Global Data	*/

CHAR	begin_disk;
forgndir *dmasect;
filespec fs1, fs2;
#ifdef	NEWFEAT
int	ncopied	= 0;		/* number of files copied */
#endif

/*page*/
/*======================================================================*/
/*				M A I N					*/
/*======================================================================*/
main (argc,argv)
int	argc;
CHAR	*argv[];
{
int	result = true;

	begin_disk = CurDisk();

	printf( "Filecopy Utility for Separated Boot  --  version %d.%d%c%c\n",
							ver,rev,mod,asm);
	printf("                                           %s\n", date);

	listUpper( argc, argv); /* convert cmdline parrameters to upper case */


	if (argc == 1 )	/* if there are no arguments on cmdline */
		result = interact (argc, argv);
 	else
		result = react (argc, argv);

/* Now exit.	*/

	DiskReset();
	SelDisk( begin_disk );	/* Reselect user's logged in drive.	*/

	if (result) {
		printf ("\nFilecopy complete.\n");
#ifdef NEWFEAT
		switch (ncopied) {
			case 0:		printf ("No files copied\n");
					break;
			case 1:		break;
			default :	printf ("%d files copied\n", ncopied);
					break;
			}
#endif
		return 0;

		}
	else {
		printf ("\nFilecopy terminated due to error.\n");
#ifdef NEWFEAT
		zabort ();
#else
		return 1;	/* Kills any pending submit file.	*/
#endif
		}
}

/*page*/
/*======================================================================*/
/*	react	- non interactive file copy				*/
/*======================================================================*/
int react ( argc, argv)
int	argc;
CHAR	*argv[];
{
int	option;

	if (argc > 3) {
		printf ("\n*** Error: too many files in command\n");
		return false;
		}
	if (argc == 3)
		option = chkoption( argv[2]);
	else
		option = error;

	switch ( option)	{
	case dir:
		if( !scanfs( argv[1], &fs1) ) return false;
		return showdir();
		break;
	case tree:
#ifdef cpm
		if( !scanfs( argv[1], &fs1) ) return false;
		return showtree();
#else
		printf( "\n*** Error: there are no path names in CP/M\n");
#endif
		break;
	case tofile:
		if( !scanfs( argv[1], &fs1) ) return false;
		if( !scanfs( argv[2], &fs2) ) return false;
		return filecopy();
		break;
	case error:
		printf( "\n*** Error: 'dir' or 'tree' or");
		printf( " second file name is missing\n");
		return false;
		break;
	default:
		interr();
		return false;
		break; 
	}
	return true;
	}

/*page*/
/*======================================================================*/
/*	showdir	- Show an MS-DOS directory for Dir command line option	*/
/*======================================================================*/
int showdir ()
{
CHAR	filename[15];
int	dmapos;

	if(driveletter (fs1.part)) {
		printf ("Sorry, you must use a partition name with the DIR option\n");
		return (false);
		}

#ifdef debug
	printf( "dir requested of %s partition\n",foreign);
#endif
	makfrgnfcb( fs1.fcb, fs1.fname, fs1.ftype);
	if (!openpart( 'D', fs1.part)) return false;
	if (!walkpath( fs1.path)) return false;
#ifdef debug
	printf("selecting disk\n");
#endif
	*(fs1.fcb) = 'D'- 'A' + 1;
#ifdef debug
	printf("about to do firstdir\n");
#endif
	dmapos = FirstDir( fs1.fcb);
#ifdef debug
	printf("firstdir returned %d\n",dmapos);
#endif
	whilå ¨ dmapoó !½ ENDdirMS) {
		dmasect = GetDMA();
		makename( filename, (dmasect+dmapos) -> fname,
				    (dmasect+dmapos) -> ftype );
		printf( "%-16.16s", filename);
		dmapos = NextDir( fs1.fcb);
		}
#ifdef debug
	printf("nextdir returned %d\n",dmapos);
#endif
	DeAssign('D');
	return true;
	}
/*page*/
/*======================================================================*/
/*	walkpath	- not working yet!				*/
/*======================================================================*/
int walkpath( path)
CHAR	*path;
{
CHAR	*slash;
int	dmapos;
forgnfcb fcb;

#ifdef debug
	printf( "walk down the directory path\n");
#endif
	if (*path == ' ' || *path == NULL) return true;
	else {
		printf ("Sorry paths not used\n");
		return false;
		}

	curdir( ROOTdir);	/* start at the root directory */
#ifdef	cpm
	while ( *path) {
		if ( *path != '\\') {
			printf( "*** Error: no initial \\\n");
			return false;
		 	}
		slash = index( path+1, '\\');
		fill( fcb, ' ', LENfcb);
		fcb.drive = 'D'- 'A' + 1;
		movetil( fcb.fname, path+1, '\\');
		dmapos = FirstDir( &fcb);
		/* check if directory not found */
		if ( dmapos == ENDdirMS) {
			printf( "*** Error: subdirectory not found\n");
			return false;
			}

		/* select new directory */
		dmasect = GetDMA();
		curdir (  ( dmasect+dmapos ) -> cluster); 

		path = slash; /* gobble up front of path name and repeat */
		}
#endif
	} 

/*page*/
/*======================================================================*/
/*	showtree	- not implemented yet				*/
/*======================================================================*/
#ifdef cpm
int showtree ()
{
	printf ( "tree requested of %s partition\n",foreign);
	makfrgnfcb( fs1.fcb, fs1.fname, fs1.ftype);
	if (!openpart( 'D', fs1.part)) return false;
	finddir( ROOTdir, "\\");
	DeAssign( 'D');
	return true;
	}

/*======================================================================*/
/*	finddir	- Not yet!						*/
/*======================================================================*/
finddir(dirname,path)
CHAR	*path;
int	*dirname;
{
CHAR	newpathname[ LENpath];
CHAR	*newpath = newpathname;
int	dmapos;

forgnfcb fcb;
forgndir adir;
forgnfcb mask;

	return false;

	printf("path=%s.\n",path);
	curdir( dirname);
	fill( mask, '?', LENfcb);
	fcb.drive = 'D';
	dmapos = FirstDir( &mask);

	while( dmapos != ENDdirMS) {
		dmasect = GetDMA();
		moven( &adir, dmasect+dmapos, LENdir);
		moven( fcb.fname, adir.fname, LENfname);
		moven( fcb.ftype, adir.ftype, LENftype);

		if ( adir.attribute == dirtype ) {
			strcpy( newpath, path);
			copyn( newpath, adir.fname, LENfname);
			strcat( newpath,"\\");
			finddir( adir.cluster, newpath);
			curdir (dirname);

			/* reposition to last dir at this level */
			FirstDir( &fcb); 
			}
		dmapos = NextDir( &mask);
		}
	
	}
#endif
/*page*/
/*======================================================================*/
/*	filecopy	- decides direction of copy and call the	*/
/*			  appropraite copy routine			*/
/*======================================================================*/
int filecopy () {
#ifdef debug
	printf ("FILECOPY. copy requested\n");
#endif

/* determine copy direction by looking at both partition names */

	if (!driveletter (fs1.part) && driveletter (fs2.part))
		return fromforeign ();
	else if ( driveletter (fs1.part) && !driveletter (fs2.part))
		return fromnative();
	else if (!driveletter (fs1.part) && driveletter (!fs2.part))
		printf ("Both %s and %s are partition names.\nFilecopy cannot determine which is CP/M\n",
			fs1.part, fs2.part);
	else
		printf ("Both %c and %c are drive letters.\nFilecopy cannot determine which is MS-DOS\n",
			*fs1.part, *fs2.part);
	return false;
	}/*filecopy*/

/*page*/
/*======================================================================*/
/*	interact	- interactive front end to the filecopy program */
/*======================================================================*/
int interact (argc, argv)
int	argc;
CHAR	*argv [];
{
#ifdef debug
CHAR	s1 [81];
CHAR	s2 [81];
#endif

	printf( "Filecopy interactive mode.\n");
#ifdef debug
	printf ("enter source:");
	clear (s1, 81, ' ');
	input (s1, 80);
	*(index (s1, ' ')) = NULL;
	printf ("enter destination:");
	clear (s2, 81, ' ');
	input (s2, 80);
	*(index (s2, ' ')) = NULL;
	argc = 3;
	argv [1] = s1;
	argv [2] = s2;
	listUpper( argc, argv); /* convert cmdline parrameters to upper case */

	return (react (argc, argv));
#endif
#ifdef DEFERED
	while( forever) {
		frompart( fs1.part);
#ifdef dbg
		printf("partition: "); disp( fs1.part, LENpart);
#endif
		if( *(fs1.part) == ' ') break;
		if( !driveletter( fs1.part))
			frompath( fs1.path);
		else
			*(fs1.path) = 0;
#ifdef dbg
		printf( "path: %s.\n", fs1.path);
#endif
		fromname( fs1.fname, fs1.ftype);
#ifdef dbg
		printf( "fname: "); disp ( fs1.fname, LENfname);
		printf(" ftype: "); disp ( fs1.ftype, LENftype);
#endif
		topart¨ fs2.part);
		switch( chkoption( fs2.part))	{
			case tofile:
				if( !driveletter( fs2.part))
					topath( fs2.path);
				else
					*(fs2.path) = 0;
				toname( fs2.fname, fs2.ftype);
				filecopy();
				break;
			case dir:
				return showdir();
				break;
			case tree:
#ifdef cpm
				return showtree();
#else
				printf("\n*** Error: there are no path ");
				printf("names in CP/M\n");
				return false;
#endif
				break;
			default:
				interr();
				return false;
				break;
			} /* end switch */
		} /* end forever */
#else
	printf ("Not implemented yet.\n");
#endif
	return true;
	}
/*page*/
/*======================================================================*/
/*	scanfs	- scan string & build  file specification		*/
/*======================================================================*/
int scanfs( filename, fs)
CHAR	*filename;
filespec *fs;
{
extern  CHAR	*findlast();
CHAR	*colon;
CHAR	*slash;

#ifdef debug
	printf( "SCANFS. scan file specification: %s\n",filename);
#endif

	fill( fs -> part, ' ', LENpart);
	colon = (index (filename, ':') ? movetil (fs->part, filename, ':') 
		: filename - 1);

#ifdef debug
	printf("scanneä partition:")» disp( fs -> part, LENpart);
#endif

	slash = findlast( colon+1, '\\');

	if ( slash)
		copyn( fs -> path, colon+1, (slash-colon) );
	else {
		slash = colon;
		*fs -> path = NULL;
		}
#ifdef debug
	printf("scanned path:%s.\n", fs -> path);
#endif

	makewild( slash+1, fs -> fname, fs -> ftype);

	return(true);
}
/*page*/
/*======================================================================*/
/*	makewild	- expand wildcards in 'filename' into '?' in	*/
/*			  fname and ftype				*/
/*======================================================================*/
makewild( filename, fname, ftype)
CHAR	*filename;
CHAR	fname[ LENfname];
CHAR	ftype[ LENftype];
{
CHAR	*next;

#ifdef debug
	printf("makewild\n");
#endif
	next = starquest( fname, filename, '.', LENfname);
#ifdef debug
	printf("\tfilename:%-8.8s\n", fname);
#endif

	starquest( ftype, next, 0, LENftype);
#ifdef debug
	printf("\tfiletype:%-3.3\n", ftype);
#endif
	if ( *fname == ' ' && *ftype == ' ') {
		fill( fname, '?', LENfname);
		fill( ftype, '?', LENftype);
		}
#ifdef debug
	printf ("\tat end, file:%-8.8s.%-3.3s\n", fname, ftype);
#endif
	}
/*page*/
/*======================================================================*/
/*	starquest	- find '*'s in string, substitute '?'s		*/
/*======================================================================*/
CHAR	*starquest( d, s, e, l)
CHAR	*d, *s, e;
int	l;
{

	for (; l && *s && *s != e && *s != '*';--l, ++s, ++d)
		*d =*s;
	if (*s == NULL || *s == e) { /* we are at the end of the string */
		if (l) clear (d, l, ' ');
		}
	else if (*s == '*') /* hit wild card */
		if (l) clear (d, l, '?');
	while (l-- && *s && *s != e)
		++s; /* scan to end of s */
	if (*s == e) ++s; /* skip past end char */
	return s;
	}

/*page*/
/*======================================================================*/
/*	fromforeign	- copy files from foriegn (MS-DOS) to 		*/
/*			  native (CP\M).				*/
/*======================================================================*/
fromforeign()
{
#define altdisk(c) ((c) == 'B' ? 'C' : 'B')
#define LENrecord 1024
forgnfcb fromfcb;
nativfcb tofcb;
CHAR	toFile   [LENpart+LENfname+LENftype+3];
CHAR	fromFile [LENpart+LENfname+LENftype+3];
CHAR	newFile  [LENpart+LENfname+LENftype+3];
int	fromfd, tofd;
CHAR	record[ LENrecord];
int	dmapos;
CHAR	writeOK = true;

#ifdef debugP
	printf( "Entering FROMFOREIGN....\n");
	printf( "\tcopying from %s system\n",foreign);
#endif

	/* Assign the foreign drive. */
	if(!openpart (altdisk (*fs2.part), fs1.part))
		return false;

	if (!walkpath( fs1.path)) return false;

#ifdef dbg
	printf("\tmaking foreign fcb: %s-8.8s.%-3.3s\n",fs1.fname,fs1.ftype);
#endif
	makfrgnfcb( fs1.fcb, fs1.fname, fs1.ftype);
	maknatvfcb (fs2.fcb, fs2.fname, fs2.ftype);
	fromfcb.drive = *(fs1.fcb) = (altdisk (*fs2.part) - 'A') + 1;
	*(fs2.fcb) = (*(fs2.part) - 'A') + 1;

#ifdef dbg
	printf( "\tfromfcb.drive: %x hex\n\t", fromfcb.drive);
#endif

	dmapos = FirstDir( fs1.fcb);
	while( dmapos != ENDdirMS) {
		dmasect = GetDMA ();

		/* Setup fcb's for file manipulation. 		*/
		/* Put filenames into 'fromfcb' and 'tofcb'.	*/
		/* Only need name and type from MSDOS directory.*/
		moven( fromfcb.fname, dmasect+dmapos, LENfname+LENftype);
		moven( &tofcb, &( fs2.fcb), LENfcb);

		/* Fill in ambiguous characters (?'s) in name template.	*/
		overlay( tofcb.fname, fromfcb.fname, LENfname);
		overlay( tofcb.ftype, fromfcb.ftype, LENftype);

		/* Setup toFile string to pass to zopen.	*/
		copymsg (toFile, fs2.part, tofcb.fname, "$$$");
		copymsg (newFile, fs2.part, tofcb.fname, tofcb.ftype);
		copymsg (fromFile, fs1.part, fromfcb.fname, fromfcb.ftype);
		printf ("Copying %s to %s\n", fromFile, newFile);

		if ( (fromfd = FileOpen( &fromfcb )) == FAIL) {
			printf(" Error. Can not open foreign 'from' file.\n");
			break;
			}
#ifdef dbg
		printf( "fileopen returned %d\n", fromfd);
#endif
		if ( (tofd = zopen( &toFile, "wb")) == -1) {
			printf(" Error. Can not open/make native 'to' file.\n");
			DoError();
			}
#ifdef NEWFEAT
		++ncopied;
#endif

		while( FileRead( fromfd, record, LENrecord) != EOF ) {
#ifdef dbg
			printf( "read succeeded\n");
			Show_128byte_buffer (record);
#endif
			if ( zwrite( tofd, record, LENrecord) != LENrecord ) {
				printf(" Out of space on CP/M disk.\n");
				writeOK = false;
				break;
				}	
			}
#ifdef dbg
		printf( "end of file\n");
#endif
		if ( zclose( tofd) == -1 ) {
			printf(" Fatal Error.");
			printf(" Failure to close an opened native 'to' file.\n");
		    	DoError();
			}

		/* rename temp file to new file name */
		rename (toFile, newFile);


		dmapos = (writeOK ? posnextdir (&fromfcb, fs1.fcb, FROMforeign)
			: ENDdirMS);
		FreeFile (fromfd);

		} /*while dmapos != ENDdirMS*/

	/* DeAssign the foreign drive. */
	DeAssign (altdisk (*fs2.part));
	return true;
	}
/*page*/
/*======================================================================*/
/*	fromnative	- copy files from native (CP/M) to 		*/
/*			  foreign (MS-DOS)				*/
/*======================================================================*/
fromnative()
{
forgnfcb tofcb;
nativfcb fromfcb;
CHAR	toFile   [LENpart+LENfname+LENftype+3]; /* d:nnnnnnnn.ttt */
CHAR	fromFile [LENpart+LENfname+LENftype+3]; /* d:nnnnnnnn.ttt */
int	fromfd, tofd;
CHAR	record[ LENrecord];
int	dmapos;
CHAR	i, writeOK;

#ifdef debugP
	printf( "p.FromNative\n\n");
	printf¨ "copyinç froí %ó system\n",native);
#endif
	/* Assign the foreign drive. */
	if (!openpart (altdisk (*fs1.part), fs2.part))
		return false;

	if (!walkpath( fs2.path)) return false;
	makfrgnfcb( fs2.fcb, fs2.fname, fs2.ftype);
	maknatvfcb( fs1.fcb, fs1.fname, fs1.ftype);
	*(fs2.fcb) = altdisk (*fs1.part) - 'A' + 1;
	*(fs1.fcb) = (*(fs1.part) - 'A') + 1;

	dmapos = SrchFrst( fs1.fcb);

#ifdef dbg1
	printf("\tdmapos from first search first: %x hex\n", dmapos);
#endif
	while( dmapos != ENDdir) {

#ifdef dbg1
		printf("\tdmapos from search: %x hex\n", dmapos);
#endif
		dmasect = GetDMA();
		/* Setup tofcb and from fcb.	*/
		moven( &fromfcb, dmasect+dmapos, LENfcb);
		/* Drive overlayed in last statement.*/
		fromfcb.drive = *(fs1.fcb);
		/* Do overlay the whole fcb for tofcb 
		   since fs2.fcb is complete.     */
		moven( &tofcb, &(fs2.fcb), LENfcb);

		/* Fill in ambiguous letters (?'s) in template.	*/
		overlay( tofcb.fname, fromfcb.fname, LENfname);
		overlay( tofcb.ftype, fromfcb.ftype, LENftype);
#ifdef dbg1
		printf ("\tSetup fromFile.\n");
#endif
		/* Set up string 'fromFile'.	*/
		copymsg (fromFile, fs1.part, fromfcb.fname, fromfcb.ftype);
		copymsg (toFile, fs2.part, tofcb.fname, tofcb.ftype);
		printf ("Copying %s to %s\n",
			fromFile, toFile);  /* copy message NOT debugging! */
#ifdef dbg1
		printf("\tDo FileMake with tofcb.\n");
#endif
		if ((tofd = FileMake( &tofcb)) == FAIL) {
			printf(" Out of directory space on MSDOS drive.\n");
			zabort();
	    		}
	if ( (fromfd = zopen( &fromFile, "rb")) == -1 ) {
		printf(" Fatal Error. Can not open a native 'from' file.\n");
		DoError ();	/* This aborts rest of program. */
		}

#ifdef NEWFEAT
	++ncopied;
#endif

	writeOK = true;
	while ( zread (fromfd, record, LENrecord))
		if ( FileWrite (tofd, record, LENrecord) == FAIL ) {
			printf (" Out of room on partition %s.\n", fs2.part);
			writeOK = false;
			break;
			}			
	if (zclose (fromfd) == -1 ) {
		printf (" Fatal Error.");
		printf (" Failure to close an opened native 'from' file.\n");
		DoError ();
		return false;
	    	}

	if (writeOK) {
		FileClose (tofd); /* FileClose does its own error checking. */
		dmapos = posnextdir (&fromfcb, fs1.fcb, FROMnative);
		}
	else
		dmapos = ENDdir;

	}/*while dmapos != ENDdir*/

	/* DeAssign the foreign drive. */
	DeAssign (altdisk (*fs1.part));
	return true;
	}
/*page*/
/*======================================================================*/
/*	DoError - Report Aztec C IO errors				*/
/*======================================================================*/
DoError()
{
    switch( errno ) { 
	case ENOENT:			/* -1 */
		printf(" error ENOENT.\n");
		break;
	case E2BIG:			/* -2 */
		printf(" error E2BIG.\n");
		break;
	case EBADF:			/* -3 */
		printf(" error EBADF.\n");
		break;
	case ENOMEM:			/* -4 */
		printf(" error ENOMEM.\n");
		break;
	case EEXIST:			/* -5 */
		printf(" error EEXIST.\n");
		break;
	case EINVAL:			/* -6 */
		printf(" error EINVAL.\n");
		break;
	case ENFILE:			/* -7 */
		printf(" error ENFILE.\n");
		break;
	case EMFILE:			/* -8 */
		printf(" error EMFILE.\n");
		break;
	case ENOTTY:			/* -9 */
		printf(" error ENOTTY.\n");
		break;
	case EACCES:			/* -10 */
		printf(" error EACCES.\n");
		break;
	case ERANGE:			/* -20 */
		printf(" error ERANGE.\n");
		break;
	case EDOM:			/* -21 */
		printf(" error EDOM.\n");
		break;

	default:
		printf(" Unknown error number: %x hex   %d decimal.\n",
			errno, errno);
	} /*switch*/

	zabort();

	} /*DoError*/

/*======================================================================*/
/*			END of FILECOPY.C				*/
/*======================================================================*/


