-- DFSubr.Mesa, last edit January 3, 1983 6:01 pm
-- Pilot 6.0 / Mesa 7.0

DIRECTORY
  File: TYPE USING [Capability, nullCapability],
  Stream: TYPE USING [Handle],
  Subr: TYPE USING[TTYProcs],
  TimeStamp: TYPE USING[Null, Stamp];

DFSubr: DEFINITIONS = {

Criterion: TYPE = {none, update, notequal};

DF: TYPE = LONG POINTER TO DFFileRecord;
DFFileRecord: TYPE = RECORD[
	host: LONG STRING ← NIL,		-- ivy
	directory: LONG STRING ← NIL,	-- schmidt>model
	shortname: LONG STRING ← NIL,	-- junk.mesa
	version: CARDINAL ← 0,		-- 23
	createtime: LONG CARDINAL ← 0,	-- > 0 is create time from leader pg.
	comment: LONG STRING ← NIL,	-- comment before this line
	recorder: LONG STRING ← NIL,	-- describebcd, verifydf, releasetool
	releaseHost: LONG STRING ← NIL,	-- release on Ivy
	releaseDirectory: LONG STRING ← NIL,	-- release as Cedar>Top
	atsign: BOOL ← FALSE,	-- indirect this df file
	criterion: Criterion ← none, 
					-- none, notequal => xfer if ~= dates
					-- update => like retrieve/U
	topmark: BOOL ← FALSE,	-- if T then this is top bcd in DF
	newOnly: BOOL ← FALSE,	-- filename preceded by ~, 
				-- indicating retrieve only if not already on disk
	public: BOOL ← FALSE,	-- if T then directory was Public
	publicOnly: BOOL ← FALSE,	-- if T then {PublicOnly} in filename
	readonly: BOOL ← FALSE,	-- readonly directory
	cameFrom: BOOL ← FALSE,	-- T => CameFrom, F=> ReleaseAs
	parentCameFrom: BOOL ← FALSE,	-- used by ReleaseTool
	versionstamp: TimeStamp.Stamp ← TimeStamp.Null, -- used by DescribeBcd & VerifyDF
	presentonlocaldisk: BOOL ← FALSE,-- file is on local disk
	cap: File.Capability ← File.nullCapability,
	using: UsingSeq ← NIL,		-- using list for df file
	isdefns: BOOL ← FALSE,	-- used by describebcd
	systemfile: BOOL ← FALSE,	-- is a Mesa system file
	eval: BOOL ← FALSE,		-- has been evaluated in EvalBcds
	need: BOOL ← FALSE,		-- need to retrieve this file
	exportsAnalyzed: BOOL ← FALSE,	-- used by FlattenDF
	includeAnalyzed: BOOL ← FALSE	-- used by FlattenDF
	];

UsingSeq: TYPE = LONG POINTER TO UsingSeqRecord;
-- string entries may be NIL
UsingSeqRecord: TYPE = RECORD[
	zone: UNCOUNTED ZONE ← NIL,	-- the zone the strings are in
	size: CARDINAL ← 0,
	body: SEQUENCE maxsize: CARDINAL OF LONG STRING	-- the strings
	];
	
ZoneType: TYPE = {shared, single, huge};

DFSeq: TYPE = LONG POINTER TO DFSeqRecord;
-- don't change this record without looking at AllocSpecialSeq in DFSubrImpl
DFSeqRecord: TYPE = RECORD[
	dfzone: UNCOUNTED ZONE ← NIL,
	zoneType: ZoneType ← shared,
	size: CARDINAL ← 0,
	trailingcomment: LONG STRING ← NIL,
	ivyHost: LONG STRING ← NIL,	-- if huge, then "Ivy"
	indigoHost: LONG STRING ← NIL,	-- if huge then "Indigo"
	body: SEQUENCE maxsize: CARDINAL OF DFFileRecord
	];
	
-- PROGRAMS (does NOT need to be started explicitly)
DFSubrImpl, DFParserImpl: PROGRAM;

-- PROCS (defined in DFParserImpl.Mesa)
DFEntryProcType: TYPE = PROC[dfEntry: DF];

-- be sure to check version >0, createtime = 0, and criterion = none 
-- to determine if wants explicit version
InterestingNestedDFProcType: TYPE = PROC[
	host, directory, shortname, ancestor, immediateParent: LONG STRING, 
	version, nLevel: CARDINAL, createtime: LONG CARDINAL, 
	driverUsingSeq, innerUsingSeq: UsingSeq, dfEntry: DF,
	entryIsReadonly, publicOnly: BOOL, criterion: Criterion];

-- if noremoteerrors is true, don't complain if a file doesn't
-- appear to have a remote place
-- if forceReadonly then make every entry in this DF file be ReadOnly
-- if omitNonPublic, then don't parse them into dfseq
-- dffilename is for error messages
ParseStream: PROC[sh: Stream.Handle, dfseq: DFSeq, dffilename: LONG STRING,
	using: UsingSeq, noremoteerrors, forceReadonly, omitNonPublic: BOOL,
	h: Subr.TTYProcs, interestingNestedDF: InterestingNestedDFProcType ← NIL, 
	dfEntryProc: DFEntryProcType ← NIL,
	ancestor: LONG STRING ← NIL, nLevel: CARDINAL ← 0];

-- PROCS (defined in DFSubrImpl)
-- remember this stuff uses its own HugeZone
-- allocation
-- if useHugeZone then only uses HugeZone
AllocateDFSeq: PROC[maxEntries: CARDINAL, zoneType: ZoneType] 
	RETURNS[dfseq: DFSeq];
NextDF: PROC[dfseq: DFSeq] RETURNS[df: DF];
FreeDFSeq: PROC[pdfseq: POINTER TO DFSeq];
	
-- input/output

WriteOut: PROC[dfseq: DFSeq, topLevelFile: STRING, outputStream: Stream.Handle,
	print, altoCompatibility: BOOL ← FALSE, wrapUsingLists: BOOL ← TRUE];
FlattenDF: PROC[dfseq: DFSubr.DFSeq, dffilename: LONG STRING, 
	h: Subr.TTYProcs, checkForOverwrite, allowForceReadOnly: BOOL ← TRUE, 
	setRecorder, printStatus, skipCameFrom, tryDollars: BOOL ← FALSE];

TooManyEntries: ERROR;	-- raised by FlattenDF when dfseq fills up

-- UsingSeq procedures
-- oldusing may be NIL
AppendToUsingSeq: PROC[oldusing: UsingSeq, shortname: LONG STRING, zone: UNCOUNTED ZONE]
	RETURNS[newusing: UsingSeq];
UsingEmpty: PROC[usingseq: UsingSeq] RETURNS[empty: BOOL];
IntersectUsing: PROC[driver, limiter: UsingSeq] RETURNS[newusing: UsingSeq];
CopyUsing: PROC[limiter: UsingSeq] RETURNS[newusing: UsingSeq];
FreeUsingSeq: PROC[using: UsingSeq];
	
-- utilities
ReadInDir: PROC[dfseq: DFSeq];
LookupDF: PROC[dfseq: DFSeq, shortname: LONG STRING] RETURNS[df: DF];

-- fullname is readonly
-- any of host, directory, short may be NIL
-- if mustbedir is TRUE then if long does not end in a '>
-- the tail is assumed to be part of the directory, not the short,
-- e.g. "schmidt>pilot" is all a directory if mustbedir is TRUE
StripLongName: PROC[fullname, host, directory, short: LONG STRING, 
	mustbedir: BOOL ← FALSE] RETURNS[version: CARDINAL];

SortByFileName, SortByCap: PROC[dfseq: DFSeq, min, max: CARDINAL, 
	ignorehostanddir: BOOL ← FALSE];
CompareDFs: PROC[dfleft, dfright: DF, ignorehostanddir: BOOL ← FALSE] 
	RETURNS[res: INTEGER];
InsertCRs: PROC[dfseq: DFSeq];

}.