-- File: Leaf.mesa
-- Last edited by Levin:   3-Feb-82  9:26:38
-- Loosely derived (after extensive discussions with Wobber) from Butterfield's
--   LeafDefs of July 27, 1979  2:11 PM.

DIRECTORY
  Environment USING [Byte],
  PupTypes USING [PupSocketID, PupType];

Leaf: DEFINITIONS =
  BEGIN


  -- Types and Related Constants --

  LeafType: TYPE = MACHINE DEPENDENT {
    error(0), open(1), close(2), delete(3), length(4), truncate(5),
    read(6), write(7), reset(8), noop(9), telnet(10), params(11), (31)};

  LeafOp: TYPE = MACHINE DEPENDENT RECORD [
    type(0:0..4): LeafType, sense(0:5..5): {request, reply} ← request,
    length(0:6..15): CARDINAL [0..532]];

  openOp: LeafOp = [type: open, length: 2*SIZE[open RequestObject]];
  closeOp: LeafOp = [type: close, length: 2*SIZE[close RequestObject]];
  deleteOp: LeafOp = [type: delete, length: 2*SIZE[delete RequestObject]];
  lengthOp: LeafOp = [type: length, length: 2*SIZE[length RequestObject]];
  truncateOp: LeafOp = [type: truncate, length: 2*SIZE[truncate RequestObject]];
  readOp: LeafOp = [type: read, length: 2*SIZE[read RequestObject]];
  writeOp: LeafOp = [type: write, length: 2*SIZE[write RequestObject]];
  resetOp: LeafOp = [type: reset, length: 2*SIZE[reset RequestObject]];
  paramsOp: LeafOp = [type: params, length: 2*SIZE[params RequestObject]];

  -- All strings in the reset and open ops have the form:
  -- LeafString: TYPE = MACHINE DEPENDENT RECORD [
  --   length: CARDINAL, text: ARRAY [0..0) OF CHARACTER];

  -- Note:  the op.length field for reset, open, and write must include the entire
  -- opSpecific body, including the variable length data that follows the fixed parts
  -- declared below.

  Request: TYPE = LONG POINTER TO RequestObject;
  OpenRequest: TYPE = LONG POINTER TO open RequestObject;
  CloseRequest: TYPE = LONG POINTER TO close RequestObject;
  DeleteRequest: TYPE = LONG POINTER TO delete RequestObject;
  TruncateRequest: TYPE = LONG POINTER TO truncate RequestObject;
  ReadRequest: TYPE = LONG POINTER TO read RequestObject;
  WriteRequest: TYPE = LONG POINTER TO write RequestObject;
  ResetRequest: TYPE = LONG POINTER TO reset RequestObject;
  ParamsRequest: TYPE = LONG POINTER TO params RequestObject;

  RequestObject: TYPE = MACHINE DEPENDENT RECORD [
    op: LeafOp,
    opSpecific:
      SELECT COMPUTED LeafType FROM
	params => [
	  packetDataBytes: CARDINAL,  -- server's default is 532
	  fileLockTimeout: FiveSeconds ← 0,  -- server's default is 10 minutes
	  connectionTimeout: FiveSeconds ← 0],  -- server's default is 12 hours
	reset => [
	  which: Resetee ← thisHost
	  -- primaryUserName string
	  -- primaryPassword string
	  ],
	open => [
	  handle: Handle ← noHandle,
	  read: BOOLEAN ← TRUE, write, extend, multiple, create: BOOLEAN ← FALSE,
	  vExplicit: {no, old, nextOrOld, any} ← any,
	  vDefault: {no, lowest, highest, next} ← highest,
	  leaderInfo, listMultiple: BOOLEAN ← FALSE,
	  fill: [0..31] ← 0
	  -- primaryUserName string
	  -- primaryPassword string
	  -- secondaryUserName string
	  -- secondaryPassword string
	  -- fileName string
	  ],
	close, delete => [handle: Handle],
	truncate => [handle: Handle, eofAddress: FileAddress],
	read => [
	  handle: Handle, address: FileAddress, length: ByteCount,
	  rate: Rate ← anyRate],
	write => [
	  handle: Handle, address: FileAddress, length: ByteCount,
	  writeBody:
	    SELECT OVERLAID * FROM
	      writeWords => [writeWords: ARRAY [0..0) OF WORD],
	      writeBytes => [writeBytes: PACKED ARRAY [0..0) OF Environment.Byte],
	      writeChars => [writeChars: PACKED ARRAY [0..0) OF CHARACTER],
	      ENDCASE],
	-- not presently used --
	error => NULL,
	noop => NULL,
	-- not presently implemented --
	length => [handle: Handle],
	telnet => NULL,
	ENDCASE];

  openAns: LeafOp = [type: open, sense: reply, length: 2*SIZE[open AnswerObject]];
  closeAns: LeafOp = [type: close, sense: reply, length: 2*SIZE[close AnswerObject]];
  deleteAns: LeafOp = [type: delete, sense: reply, length: 2*SIZE[delete AnswerObject]];
  lengthAns: LeafOp = [type: length, sense: reply, length: 2*SIZE[length AnswerObject]];
  truncateAns: LeafOp = [type: truncate, sense: reply, length: 2*SIZE[truncate AnswerObject]];
  readAns: LeafOp = [type: read, sense: reply, length: 2*SIZE[read AnswerObject]];
  writeAns: LeafOp = [type: write, sense: reply, length: 2*SIZE[write AnswerObject]];
  resetAns: LeafOp = [type: reset, sense: reply, length: 2*SIZE[reset AnswerObject]];
  paramsAns: LeafOp = [type: params, sense: reply, length: 2*SIZE[params AnswerObject]];

  Answer: TYPE = LONG POINTER TO AnswerObject;
  OpenAnswer: TYPE = LONG POINTER TO open AnswerObject;
  CloseAnswer: TYPE = LONG POINTER TO close AnswerObject;
  DeleteAnswer: TYPE = LONG POINTER TO delete AnswerObject;
  TruncateAnswer: TYPE = LONG POINTER TO truncate AnswerObject;
  ReadAnswer: TYPE = LONG POINTER TO read AnswerObject;
  WriteAnswer: TYPE = LONG POINTER TO write AnswerObject;
  ResetAnswer: TYPE = LONG POINTER TO reset AnswerObject;
  ParamsAnswer: TYPE = LONG POINTER TO params AnswerObject;

  AnswerObject: TYPE = MACHINE DEPENDENT RECORD [
    op: LeafOp,
    opSpecific:
      SELECT COMPUTED LeafType FROM
	error => [error: IfsError, errorOp: LeafOp, handle: Handle],
	reset => NULL,
	params => [op: CARDINAL, undefined: CARDINAL],
	open => [handle: Handle, eofAddress: FileAddress],
	close, delete, truncate => [handle: Handle],
	read => [
	  handle: Handle, address: FileAddress, length: ByteCount,
	  readBody:
	    SELECT OVERLAID * FROM
	      readWords => [readWords: ARRAY [0..0) OF WORD],
	      readBytes => [readBytes: PACKED ARRAY [0..0) OF Environment.Byte],
	      readChars => [readChars: PACKED ARRAY [0..0) OF CHARACTER],
	      ENDCASE],
	write => [
	  handle: Handle, address: FileAddress, length: ByteCount, rate: Rate],
	-- not presently expected --
	noop => NULL,
	-- not presently implemented --
	length => [handle: Handle, eofAddress: FileAddress],
	telnet => NULL,
	ENDCASE];

  FiveSeconds: TYPE = CARDINAL;  -- units of five seconds; zero means server default

  FileAddress: TYPE = MACHINE DEPENDENT RECORD [
    opSpecific(0:0..4): OpSpecificFileAddress ← [read[]],
    high(0:5..15): [0..2047], low(1:0..15): CARDINAL];

  OpSpecificFileAddress: TYPE = MACHINE DEPENDENT RECORD [
    SELECT COMPUTED LeafType FROM
      open, length, truncate => [fill: [0..31] ← 0],
      read, write =>
	[mode: {anywhere, noHoles, dontExtend, checkExtend} ← anywhere,
	newEOF: BOOLEAN ← FALSE,
	fill: [0..3] ← 0],
      ENDCASE];

  ByteCount: TYPE = CARDINAL;

  Rate: TYPE = CARDINAL;
  anyRate: Rate = 0;

  Handle: TYPE = CARDINAL;
  noHandle: CARDINAL = 0;

  Resetee: TYPE = MACHINE DEPENDENT {thisHost(0), fileLocks(1), allHosts(177777B)};

  IfsError: TYPE = MACHINE DEPENDENT {
    ok(0),
    nameMalformed(201), illegalChar(202), illegalStar(203), illegalVersion(204),
    nameTooLong(205), illegalDIFAccess(206), fileNotFound(207), accessDenied(208),
    fileBusy(209), dirNotFound(210), allocExceeded(211), fileSystemFull(212),
    createStreamFailed(213), fileAlreadyExists(214), fileUndeletable(215),
    userName(216), userPassword(217), filesOnly(218),
    connectName(219), connectPassword(220),
    brokenLeaf(1001), unimplementedOp(1010), badHandle(1011), fileTooLong(1012),
    illegalTruncate(1013), illegalRead(1015), illegalWrite(1016), (177777B)};


  -- Miscellaneous Declarations --

  leafSocket: PupTypes.PupSocketID = [0, 43B];
  ptLeaf: PupTypes.PupType = LOOPHOLE[260B];


  END.