-- StreamDefs.Mesa  Edited by Sandman on June 30, 1980  5:05 PM
-- Copyright  Xerox Corporation 1979, 1980

DIRECTORY
  AltoDefs USING [BYTE, CharsPerPage, PageNumber],
  AltoFileDefs USING [FA, vDA],
  Mopcodes USING [zLDIV, zMUL, zPUSH],
  SegmentDefs USING [
    AccessOptions, Append, DefaultAccess, FileHandle, Read, ReadWrite,
    ReadWriteAppend, Write, WriteAppend];

StreamDefs: DEFINITIONS =
  BEGIN

  KeyBufChars: PRIVATE INTEGER = 80;

  StreamHandle: TYPE = POINTER TO StreamObject;
  KeyboardHandle: TYPE = POINTER TO Keyboard StreamObject;
  DisplayHandle: TYPE = POINTER TO Display StreamObject;
  DiskHandle: TYPE = POINTER TO Disk StreamObject;
  OtherStreamHandle: TYPE = POINTER TO Other StreamObject;

  StreamObject: TYPE = RECORD [
    reset: PROCEDURE [StreamHandle],
    get: PROCEDURE [StreamHandle] RETURNS [UNSPECIFIED],
    putback: PROCEDURE [StreamHandle, UNSPECIFIED],
    put: PROCEDURE [StreamHandle, UNSPECIFIED],
    endof: PROCEDURE [StreamHandle] RETURNS [BOOLEAN],
    destroy: PROCEDURE [StreamHandle],
    link: StreamHandle,
    body:
      SELECT type: * FROM
	Keyboard => [
	  in, out: CARDINAL, buffer: PACKED ARRAY [0..KeyBufChars) OF CHARACTER],
	Display => [
	  clearCurrentLine: PROCEDURE [stream: StreamHandle],
	  clearLine: PROCEDURE [stream: StreamHandle, line: CARDINAL],
	  clearChar: PROCEDURE [stream: StreamHandle, char: CHARACTER],
	  type: UNSPECIFIED,
	  data: POINTER],
	Disk => [
	  eof, dirty: BOOLEAN,
	  read, write, append: BOOLEAN,
	  unit: [1..2],
	  index, size: CARDINAL,
	  page: AltoDefs.PageNumber,
	  char: CARDINAL,
	  buffer: RECORD [
	    SELECT OVERLAID * FROM
	      byte => [byte: POINTER TO PACKED ARRAY [0..0) OF AltoDefs.BYTE],
	      word => [word: POINTER TO ARRAY [0..0) OF WORD],
	      ENDCASE],
	  file: SegmentDefs.FileHandle,
	  das: ARRAY {last, current, next} OF AltoFileDefs.vDA,
	  getOverflow: PROCEDURE [StreamHandle],
	  savedGet: PROCEDURE [StreamHandle] RETURNS [UNSPECIFIED],
	  putOverflow: PROCEDURE [StreamHandle],
	  savedPut: PROCEDURE [StreamHandle, UNSPECIFIED]],
	Other => [type: UNSPECIFIED, data: POINTER],
	ENDCASE];

  StreamError: SIGNAL [stream: StreamHandle, error: StreamErrorCode];

  StreamErrorCode: TYPE = {
    StreamType, StreamAccess, StreamOperation, StreamPosition, StreamEnd,
    StreamBug};

  -- extensions applicable to keyboard streams


  CreateKeyStream: PROCEDURE RETURNS [KeyboardHandle];
  GetDefaultKey, GetCurrentKey: PROCEDURE RETURNS [KeyboardHandle];
  OpenKeyStream, CloseKeyStream: PROCEDURE [stream: StreamHandle];
  StartKeyHandler, StopKeyHandler, DestroyKeyHandler: PROCEDURE;

  trackCursor: BOOLEAN;
  CursorTrack: PROCEDURE [b: BOOLEAN] = INLINE BEGIN trackCursor ← b END;

  userAbort: BOOLEAN;
  ControlDELtyped: PROCEDURE RETURNS [BOOLEAN] = INLINE
    BEGIN RETURN[userAbort] END;

  ResetControlDEL: PROCEDURE = INLINE BEGIN userAbort ← FALSE END;

  GetDefaultDisplayStream: PROCEDURE RETURNS [DisplayHandle];

  -- extensions applicable to disk streams

  StreamPosition: TYPE = LONG CARDINAL;

  StreamIndex: TYPE = RECORD [page: AltoDefs.PageNumber, byte: CARDINAL];

  AccessOptions: TYPE = SegmentDefs.AccessOptions;
  Read: AccessOptions = SegmentDefs.Read;
  Write: AccessOptions = SegmentDefs.Write;
  Append: AccessOptions = SegmentDefs.Append;
  ReadWrite: AccessOptions = SegmentDefs.ReadWrite;
  WriteAppend: AccessOptions = SegmentDefs.WriteAppend;
  ReadWriteAppend: AccessOptions = SegmentDefs.ReadWriteAppend;

  DefaultAccess: AccessOptions = SegmentDefs.DefaultAccess;

  NewByteStream, NewWordStream: PROCEDURE [name: STRING, access: AccessOptions]
    RETURNS [DiskHandle];
  FileNameError: SIGNAL [name: STRING];
  CreateByteStream, CreateWordStream: PROCEDURE [
    file: SegmentDefs.FileHandle, access: SegmentDefs.AccessOptions]
    RETURNS [DiskHandle];
  OpenDiskStream, CloseDiskStream: PROCEDURE [stream: StreamHandle];
  CleanupDiskStream, TruncateDiskStream: PROCEDURE [stream: StreamHandle];
  FileLength: PROCEDURE [stream: StreamHandle] RETURNS [StreamIndex];
  GetFA: PROCEDURE [stream: StreamHandle, fa: POINTER TO AltoFileDefs.FA];
  JumpToFA: PROCEDURE [stream: StreamHandle, fa: POINTER TO AltoFileDefs.FA];
  ReadBlock, WriteBlock: PROCEDURE [
    stream: StreamHandle, address: POINTER, words: CARDINAL] RETURNS [CARDINAL];
  GetDiskStreamList: PROCEDURE RETURNS [DiskHandle];

  -- StreamPosition Stuff


  GetPosition: PROCEDURE [stream: StreamHandle] RETURNS [StreamPosition];
  SetPosition: PROCEDURE [stream: StreamHandle, pos: StreamPosition];

  ModifyPosition: PROCEDURE [pos: StreamPosition, change: INTEGER]
    RETURNS [StreamPosition] = INLINE
    BEGIN
    RETURN[IF change < 0 AND pos <= ABS[change] THEN 0 ELSE pos + change];
    END;

  IndexToPosition: PROCEDURE [index: StreamIndex] RETURNS [StreamPosition] =
    INLINE
    BEGIN
    LongMult: PROCEDURE [CARDINAL, CARDINAL] RETURNS [LONG CARDINAL] = MACHINE
      CODE BEGIN Mopcodes.zMUL; Mopcodes.zPUSH END;

    RETURN[LongMult[index.page, AltoDefs.CharsPerPage] + index.byte];
    END;

  PositionToIndex: PROCEDURE [pos: StreamPosition] RETURNS [index: StreamIndex] =
    INLINE
    BEGIN
    LongDivMod: PROCEDURE [StreamPosition, CARDINAL]
      RETURNS [quotient, remainder: CARDINAL] = MACHINE CODE
      BEGIN Mopcodes.zLDIV; Mopcodes.zPUSH END;

      [quotient: index.page, remainder: index.byte] ← LongDivMod[
      pos, AltoDefs.CharsPerPage];
    END;

  -- StreamIndex Stuff


  GetIndex: PROCEDURE [stream: StreamHandle] RETURNS [StreamIndex];
  SetIndex: PROCEDURE [stream: StreamHandle, index: StreamIndex];
  NormalizeIndex: PROCEDURE [index: StreamIndex] RETURNS [StreamIndex];
  ModifyIndex: PROCEDURE [index: StreamIndex, change: INTEGER]
    RETURNS [StreamIndex];
  EqualIndex: PROCEDURE [i1, i2: StreamIndex] RETURNS [BOOLEAN];
  GrEqualIndex: PROCEDURE [i1, i2: StreamIndex] RETURNS [BOOLEAN];
  GrIndex: PROCEDURE [i1, i2: StreamIndex] RETURNS [BOOLEAN];

  END.