-- BringOverFrontEndImpl.Mesa, last edit February 25, 1983 2:10 pm
-- BringOverInterface is no longer exported

DIRECTORY
	BareBringOver: TYPE USING[BringOverDF, CheckThisFile,
		RecursiveLoop, State, StateRecord],
	BringOverCall: TYPE USING[],
	CWF: TYPE USING[SetWriteProcedure, WF0, WF1, WF2],
	DFSubr: TYPE USING [AllocateDFSeq, AppendToUsingSeq, Criterion, 
  	DF, DFSeq, FreeDFSeq, NextDF, StripLongName, UsingSeq],
	IO: TYPE USING[Handle, PutChar, PutF, ResetUserAbort, UserAborted],
	Rope: TYPE USING[ROPE, Text],
	Space: TYPE USING[Create, Delete, GetHandle, Handle, Map,
		nullHandle, PageFromLongPointer, virtualMemory],
	UnsafeSTP: TYPE USING[Error],
	STPSubr: TYPE USING[SetUseOfCIFS, StopSTP],
	Subr: TYPE USING [AbortMyself, CopyString, debugflg,
  	EndsIn, errorflg, FindMappedSpace, LongZone,
  	MakeTTYProcs, numberofleaders, PrintGreeting,
  	 strcpy, SubrInit, SubrStop, TTYProcs];


BringOverFrontEndImpl: PROGRAM 
IMPORTS BareBringOver, CWF, DFSubr, IO, Space, STP: UnsafeSTP, STPSubr, Subr
EXPORTS BringOverCall = {

-- MDS usage!
stdout: IO.Handle;
-- end of MDS usage

CedarBringOver: PUBLIC SAFE PROC[listOfFiles: LIST OF Rope.Text,
	usingListOfRopes: LIST OF Rope.Text, switches: ARRAY CHAR['a .. 'z] OF BOOL, 
	useCIFS: BOOL, 
	in, out: IO.Handle, 
	confirmData: REF ANY,
	Confirm: PROC[in, out: IO.Handle, data: REF ANY, msg: Rope.ROPE, dch: CHAR]
		RETURNS[CHAR]] = TRUSTED {

	h: Subr.TTYProcs ← Subr.MakeTTYProcs[in, out, confirmData, Confirm];
	dfseq: DFSubr.DFSeq ← NIL;
	usingSeq: DFSubr.UsingSeq ← NIL;
	longzone: UNCOUNTED ZONE;
	ldspace: Space.Handle ← Space.Create[size: 1, parent: Space.virtualMemory];
	stateRecord: BareBringOver.StateRecord ← [];
	state: BareBringOver.State ← @stateRecord;
	OP: PROC[CHAR] ← NIL;
	Cleanup: PROC = {
		IF ldspace ~= Space.nullHandle THEN Space.Delete[ldspace];
		ldspace ← Space.nullHandle;
		DFSubr.FreeDFSeq[@dfseq];
		STPSubr.StopSTP[];
		Subr.SubrStop[];
		IF OP ~= NIL THEN [] ← CWF.SetWriteProcedure[OP];
		OP ← NIL;
		};
	{
	ENABLE {
		STP.Error => {
			CWF.WF0["FTP Error. "L];
			IF error ~= NIL THEN 
				CWF.WF2["message: %s, code %u in Stp.Mesa\n"L, error, @code];
			Subr.errorflg ← TRUE;
			GOTO leave;
			};
		BareBringOver.CheckThisFile => -- if it gets here then there is no infinite recursive loop
			RESUME;	
		BareBringOver.RecursiveLoop => {
			CWF.WF1["Error - infinite recursive nesting of DF files using @.\n\tOne of the files involved is %s.\n"L, 
				loopfilename];
			ERROR Subr.AbortMyself;
			};
		Subr.AbortMyself, IO.UserAborted => {
			out.ResetUserAbort[];
			CWF.WF0["\nBringOver Aborted.\n"L];
			GOTO leave;
			};
		UNWIND => {
			out.ResetUserAbort[];
			Cleanup[];
			};
		};
	stdout ← h.out;
	OP ← CWF.SetWriteProcedure[MyPutChar];
	STPSubr.SetUseOfCIFS[useCIFS];
	Subr.SubrInit[256];
	longzone ← Subr.LongZone[];
	Subr.errorflg ← FALSE;
	Subr.debugflg ← FALSE;
	IF switches['a] THEN state.mustconfirm ← FALSE;
	IF switches['b] THEN state.justObjects ← TRUE;
	IF switches['f] THEN state.forceRetrieval ← TRUE;
	IF switches['p] THEN state.publicOnly ← TRUE;
	IF switches['r] THEN state.justReadOnlys ← TRUE;
	IF switches['s] THEN state.justSources ← TRUE;
	IF switches['u] THEN state.updateOnly ← TRUE;
	IF switches['v] THEN state.verify ← TRUE;
	IF switches['w] THEN state.justNonReadOnlys ← TRUE;
	state.useCIFS ← useCIFS;
	Subr.PrintGreeting["BringOver"L];
	Subr.numberofleaders ← 0;
	Space.Map[ldspace];
	FOR l: LIST OF Rope.Text ← usingListOfRopes, l.rest UNTIL l = NIL DO
		usingSeq ← DFSubr.AppendToUsingSeq[usingSeq, LOOPHOLE[l.first], longzone];
		ENDLOOP;
	FOR l: LIST OF Rope.Text ← listOfFiles, l.rest UNTIL l = NIL DO
		dfseq ← AppendToFakeDFSeq[dfseq, LOOPHOLE[l.first], usingSeq];
		usingSeq ← NIL;
		ENDLOOP;
	BareBringOver.BringOverDF[dfseq: dfseq, state: state, ldspace: ldspace, h: h];
	EXITS
	leave => NULL;
	};
	IF Subr.errorflg THEN CWF.WF0["\tErrors logged.\n"L];
	Cleanup[];
	};
	
MyPutChar: PROC[ch: CHAR] = {
	stdout.PutChar[ch];
	};
	
AppendToFakeDFSeq: PROC[oldDFSeq: DFSubr.DFSeq, fileName: LONG STRING,
		usingSeq: DFSubr.UsingSeq] RETURNS[newDFSeq: DFSubr.DFSeq] = {
	host: STRING ← [30];
	directory: STRING ← [100];
	shortname: STRING ← [100];
	version: CARDINAL;
	df: DFSubr.DF;
	
	IF oldDFSeq = NIL THEN 
		newDFSeq ← DFSubr.AllocateDFSeq[maxEntries: 50, zoneType: shared]
	ELSE IF oldDFSeq.size >= oldDFSeq.maxsize THEN {
		space: Space.Handle;
		newDFSeq ← DFSubr.AllocateDFSeq[maxEntries: oldDFSeq.size+50, zoneType: shared];
		newDFSeq.size ← oldDFSeq.size;
		newDFSeq.trailingcomment ← oldDFSeq.trailingcomment;
		FOR i: CARDINAL IN [0 .. newDFSeq.size) DO
			newDFSeq[i] ← oldDFSeq[i];
			ENDLOOP;
		space ← Subr.FindMappedSpace[Space.GetHandle[Space.PageFromLongPointer[oldDFSeq]]];
		Space.Delete[space];
		}
	ELSE newDFSeq ← oldDFSeq;
	version ← DFSubr.StripLongName[fileName, host, directory, shortname];
	IF shortname.length = 0 THEN SIGNAL Subr.AbortMyself;
	IF host.length = 0 AND directory.length ~= 0 THEN 
		Subr.strcpy[host, "Indigo"L];	-- no host, with directory, is defaulted to Indigo
	df ← DFSubr.NextDF[newDFSeq];
	df.host ← IF host.length = 0 THEN NIL ELSE Subr.CopyString[host, newDFSeq.dfzone];
	df.directory ← IF directory.length = 0 THEN NIL ELSE Subr.CopyString[directory, newDFSeq.dfzone];
	df.shortname ← Subr.CopyString[shortname, newDFSeq.dfzone];
	df.version ← version;
	df.createtime ← 0;
	df.criterion ← none;
	df.using ← usingSeq;	-- this is the using list for /o
	df.atsign ← Subr.EndsIn[shortname, ".DF"L];
	};

}.