-- GeorgeAlto.mesa  Edited by HGM on November 18, 1980  1:32 PM

DIRECTORY
  AltoFileDefs USING [FP],
  DirectoryDefs USING [EnumerateDirectory],
  Inline USING [HighByte, LowByte],
  SegmentDefs USING [
    Append, DefaultAccess, DefaultVersion, DestroyFile, FileHandle, FileNameError,
    GetFileTimes, InsertFile, NewFile, OldFileOnly, Read, ReleaseFile,
    SetFileTimes, WriteAppend],
  StreamDefs USING [
    CreateByteStream, DiskHandle, FileLength, GetPosition, IndexToPosition,
    ReadBlock, SetPosition, WriteBlock],
  File USING [Capability, nullCapability],
  Space USING [Handle],
  System USING [GreenwichMeanTime],
  George USING [BYTE, Handle];

GeorgeAlto: PROGRAM
  IMPORTS DirectoryDefs, Inline, SegmentDefs, StreamDefs EXPORTS George, Space =
  BEGIN OPEN George;


  -- S P A C E S:

  nullHandle: PUBLIC Space.Handle ← NIL;


  -- D I R E C T O R Y and F I L E S:

  CreateNewFile: PUBLIC PROCEDURE [name: STRING, pages: CARDINAL]
    RETURNS [fp: File.Capability] =
    BEGIN OPEN SegmentDefs;
    file: FileHandle ← NewFile[
      name, WriteAppend ! FileNameError => GOTO NotFound];
    fp ← [file.fp, DefaultAccess];
    EXITS NotFound => RETURN[File.nullCapability];
    END;

  EnumerateDirectory: PUBLIC PROCEDURE [
    proc: PROCEDURE [File.Capability, STRING] RETURNS [BOOLEAN]] =
    BEGIN
    MyProc: PROCEDURE [fp: POINTER TO AltoFileDefs.FP, name: STRING]
      RETURNS [BOOLEAN] =
      BEGIN
      name.length ← name.length - 1; -- stupid trailing dot
      RETURN[proc[[fp↑, SegmentDefs.DefaultAccess], name]];
      END;
    DirectoryDefs.EnumerateDirectory[MyProc];
    END;

  LookupExistingFile: PUBLIC PROCEDURE [name: STRING]
    RETURNS [fp: File.Capability] =
    BEGIN OPEN SegmentDefs;
    file: FileHandle ← NewFile[
      name, Read, OldFileOnly ! FileNameError => GOTO NotFound];
    fp ← [file.fp, DefaultAccess];
    IF file.segcount = 0 AND file.lock = 0 THEN ReleaseFile[file];
    EXITS NotFound => RETURN[File.nullCapability];
    END;

  NameToCapability: PUBLIC PROCEDURE [name: STRING, pages: CARDINAL]
    RETURNS [fp: File.Capability] =
    BEGIN OPEN SegmentDefs;
    file: FileHandle ← NewFile[
      name, Read + WriteAppend, DefaultVersion ! FileNameError => GOTO NotFound];
    fp ← [file.fp, DefaultAccess];
    IF file.segcount = 0 AND file.lock = 0 THEN ReleaseFile[file];
    EXITS NotFound => RETURN[File.nullCapability];
    END;

  DeleteFileFromDisk: PUBLIC PROCEDURE [fp: File.Capability] =
    BEGIN SegmentDefs.DestroyFile[SegmentDefs.InsertFile[@fp.fID]]; END;


  -- S T R E A M S:

  CreateAppendStream: PUBLIC PROCEDURE [fp: File.Capability] RETURNS [h: Handle] =
    BEGIN
    file: SegmentDefs.FileHandle ← SegmentDefs.InsertFile[
      @fp.fID, SegmentDefs.Append];
    h ← StreamDefs.CreateByteStream[file, SegmentDefs.Append];
    END;

  CreateInputStream: PUBLIC PROCEDURE [fp: File.Capability] RETURNS [h: Handle] =
    BEGIN
    file: SegmentDefs.FileHandle ← SegmentDefs.InsertFile[
      @fp.fID, SegmentDefs.Read];
    h ← StreamDefs.CreateByteStream[file, SegmentDefs.Read];
    END;

  CreateOutputStream: PUBLIC PROCEDURE [fp: File.Capability] RETURNS [h: Handle] =
    BEGIN
    file: SegmentDefs.FileHandle ← SegmentDefs.InsertFile[
      @fp.fID, SegmentDefs.WriteAppend];
    h ← StreamDefs.CreateByteStream[file, SegmentDefs.WriteAppend];
    END;

  Destroy: PUBLIC PROCEDURE [h: Handle] = BEGIN h.destroy[h]; END;

  GetCreateDate: PUBLIC PROCEDURE [h: Handle] RETURNS [System.GreenwichMeanTime] =
    BEGIN
    dh: StreamDefs.DiskHandle = LOOPHOLE[h];
    RETURN[SegmentDefs.GetFileTimes[dh.file].create];
    END;

  GetIndex: PUBLIC PROCEDURE [h: Handle] RETURNS [LONG CARDINAL] =
    BEGIN RETURN[StreamDefs.GetPosition[h]]; END;

  GetLength: PUBLIC PROCEDURE [h: Handle] RETURNS [LONG CARDINAL] =
    BEGIN RETURN[StreamDefs.IndexToPosition[StreamDefs.FileLength[h]]]; END;

  SetCreateDate: PUBLIC PROCEDURE [h: Handle, t: System.GreenwichMeanTime] =
    BEGIN
    dh: StreamDefs.DiskHandle = LOOPHOLE[h];
    SegmentDefs.SetFileTimes[file: dh.file, create: t];
    END;

  SetIndex: PUBLIC PROCEDURE [h: Handle, i: LONG CARDINAL] =
    BEGIN StreamDefs.SetPosition[h, i]; END;


  -- D A T A   T R A N S F E R:

  GetWords: PUBLIC PROCEDURE [h: Handle, p: POINTER, words: CARDINAL]
    RETURNS [CARDINAL] = BEGIN RETURN[StreamDefs.ReadBlock[h, p, words]]; END;

  GetByte: PUBLIC PROCEDURE [h: Handle] RETURNS [BYTE] =
    BEGIN RETURN[h.get[h]]; END;

  GetWord: PUBLIC PROCEDURE [h: Handle] RETURNS [WORD] =
    BEGIN
    left: BYTE ← h.get[h];
    right: BYTE ← h.get[h];
    RETURN[left*400B + right];
    END;

  PutWordsHitEOF: ERROR = CODE;
  PutWords: PUBLIC PROCEDURE [h: Handle, p: POINTER, words: CARDINAL] =
    BEGIN
    n: CARDINAL = StreamDefs.WriteBlock[h, p, words];
    IF n # words THEN ERROR PutWordsHitEOF;
    END;

  PutChar: PUBLIC PROCEDURE [h: Handle, c: CHARACTER] = BEGIN h.put[h, c]; END;

  PutByte: PUBLIC PROCEDURE [h: Handle, b: BYTE] = BEGIN h.put[h, b]; END;

  PutWord: PUBLIC PROCEDURE [h: Handle, w: WORD] =
    BEGIN h.put[h, Inline.HighByte[w]]; h.put[h, Inline.LowByte[w]]; END;

  END.