-- BringOverFrontEndImpl.Mesa
-- last edit February 25, 1983 2:10 pm
-- last edit May 22, 1983 3:57 pm, Russ Atkinson
-- 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, 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];
  OPNIL;
  };
 {
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;
OPCWF.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];
 };

}.