-- SMDFImpl.mesa
-- last edited by Schmidt June 1, 1983 5:45 pm
-- last edited by Satterthwaite, August 8, 1983 11:22 am

DIRECTORY
  ConvertUnsafe: TYPE USING [ToRope],
  CS: TYPE USING [RopeToString],
  DFSubr: TYPE USING [AllocateDFSeq, DF, DFSeq, FreeDFSeq, LookupDF, NextDF, WriteOut],
  FileStream: TYPE USING [GetLeaderPropertiesForCapability],
  IO: TYPE USING [PutF, string],
  Rope: TYPE USING [Fetch, IsEmpty, Length, ROPE, Text],
  SMCommentTableOps: TYPE USING [FindNext],
  SMDF: TYPE USING [],
  SMEval: TYPE USING [CompMod],
  SMFI: TYPE USING [BcdFileInfo, SrcFileInfo],
  SMFIOps: TYPE USING [GetExtFromParse],
  SMOps: TYPE USING [MS],
  SMTree: TYPE Tree USING [Handle, Link],
  SMTreeOps: TYPE USING [Scan, ScanSons],
  Stream: TYPE USING [Delete, Handle, PutChar],
  Subr: TYPE USING [CopyString, NewStream, SubrStop, Write],
  ViewerClasses: TYPE USING [Viewer],
  ViewerOps: TYPE USING [FindViewer, RestoreViewer];


SMDFImpl: CEDAR MONITOR 
    IMPORTS
      ConvertUnsafe, CS, DFSubr, FileStream, IO, Rope, SMCommentTableOps, SMFIOps,
      SMTreeOps, Stream, Subr, ViewerOps
    EXPORTS SMDF ~ {

 -- monitor is used to protect the DF software, which cannot
 -- be called in parallel

  ConstructDFFile: PUBLIC ENTRY PROC[ms: SMOps.MS, top: SMTree.Link] ~ TRUSTED {
    ENABLE UNWIND => NULL;
    dfFileName: STRING ← "Manufactured.DF"L;
    dfseq: DFSubr.DFSeq;
    sh: Stream.Handle;
    viewer: ViewerClasses.Viewer;
    comment: Rope.ROPE;
	
    AnalSons: SMTreeOps.Scan ~ TRUSTED {
      WITH t SELECT FROM
	applyNode: SMTree.Handle =>
	  SELECT applyNode.name FROM
	    $apply => {
	      ext: SMTree.Link ← SMFIOps.GetExtFromParse[applyNode];
	      IF ext ~= NIL AND ISTYPE[ext, SMEval.CompMod] THEN { 
		compMod: SMEval.CompMod ← NARROW[ext];
		AddToDFFile[ms, dfseq, compMod]};
	      SMTreeOps.ScanSons[applyNode, AnalSons]};
	    ENDCASE => SMTreeOps.ScanSons[applyNode, AnalSons];
	ENDCASE => NULL;
      };

    dfseq ← DFSubr.AllocateDFSeq[maxEntries~500, zoneType~shared];
    SMTreeOps.ScanSons[top, AnalSons];
    sh ← Subr.NewStream[dfFileName, Subr.Write];
    DFSubr.WriteOut[dfseq~dfseq, topLevelFile~NIL, outputStream~sh];
    -- now add first comment for Imports, etc.
    comment ← SMCommentTableOps.FindNext[ms.comments, 0].text;
    -- the first two chars are skipped, they are undoubtedly - followed by -
    FOR i: INT IN [2 .. comment.Length[]) DO Stream.PutChar[sh, comment.Fetch[i]] ENDLOOP;
    Stream.Delete[sh];
    DFSubr.FreeDFSeq[@dfseq];
    viewer ← ViewerOps.FindViewer[ConvertUnsafe.ToRope[dfFileName]];
    IF viewer ~= NIL THEN {
      IF viewer.newVersion THEN 
	ms.out.PutF["Warning - you are already editing %s.\n", IO.string[dfFileName]]
      ELSE ViewerOps.RestoreViewer[viewer]};
    ms.out.PutF["DF file written on file Manufactured.DF\n"];
    Subr.SubrStop[];	-- shuts down old DF world
    };
	
  AddToDFFile: PROC[
      ms: SMOps.MS, dfseq: DFSubr.DFSeq, compMod: SMEval.CompMod] ~ TRUSTED {
    fiSrc: SMFI.SrcFileInfo ← compMod.fiSrc;
    fiBcd: SMFI.BcdFileInfo ← compMod.fiBcd;
    createtime: LONG CARDINAL ← 0;
    AddAFile[ms, dfseq, fiSrc.host, fiSrc.directory, fiSrc.shortname, fiSrc.version];
    IF fiBcd.bcdPresent THEN
      createtime ← FileStream.GetLeaderPropertiesForCapability[fiBcd.bcdCap].create;
    AddAFile[ms, dfseq, fiBcd.host, fiBcd.directory, fiBcd.shortname, createtime]};
	
  AddAFile: PROC[
      ms: SMOps.MS, dfseq: DFSubr.DFSeq,
      host, directory, shortname: Rope.Text, createTime: LONG CARDINAL] ~ TRUSTED {
    df: DFSubr.DF;
    str: STRING ← [100];
    CS.RopeToString[to~str, from~shortname];
    IF DFSubr.LookupDF[dfseq, str] ~= NIL THEN RETURN;
    df ← DFSubr.NextDF[dfseq];
    IF df = NIL THEN RETURN; 	-- too big
    df.host ← Subr.CopyString[
	IF Rope.IsEmpty[host] THEN "Unknown"L ELSE LOOPHOLE[host], dfseq.dfzone];
    df.directory ← Subr.CopyString[
	IF Rope.IsEmpty[directory] THEN "Unknown"L ELSE LOOPHOLE[directory], dfseq.dfzone];
    df.shortname ← Subr.CopyString[LOOPHOLE[shortname], dfseq.dfzone];
    df.version ← 0;
    df.createtime ← createTime};
	
  }.