-- Copyright (C) 1987 by Xerox Corporation.  All rights reserved.
-- Stub file  was translated on March 25, 1987 3:05:53 pm PST by Lupine of January 22, 1987 5:37:32 pm PST
-- Source interface AlpineFile came from file AlpineFile.bcd, which was created on March 25, 1987 12:09:49 pm PST with version stamp 257#330#25514770454 from source of June 16, 1986 10:44:04 am PDT.

-- The RPC stub modules for AlpineFile are:
--   AlpineFileRpcControl.mesa;
--   AlpineFileRpcClientImpl.mesa;
--   AlpineFileRpcBinderImpl.mesa;
--   AlpineFileRpcServerImpl.mesa.

-- The parameters for this translation are:
--   Target language = Cedar
--   Default parameter passing = VALUE
--   Deallocate server heap arguments = TRUE
--   Inline RpcServerImpl dispatcher stubs = FALSE
--   Declare signals = FALSE
--   Warn about short POINTER ("MDS") allocations = TRUE
--   Maximum number of dynamic heap NEWs = 50, MDS NEWs = 50
--   Acceptable parameter protocols = VersionRange[1..1].


DIRECTORY
  AlpineEnvironment,
  AlpineFile,
  AlpineFileRpcControl USING [InterMdsCallsOnly, LupineProtocolVersion,
      ProcedureIndex, SignalIndex],
  RPC USING [EncryptionKey, InterfaceName, Principal, standardZones,
      Zones],
  RPCLupine --USING SOME OF [Call, DataLength, Dispatcher, ExportHandle,
      -- ExportInterface, GetStubPkt, maxDataLength, maxPrincipalLength,
      -- maxShortStringLength, pktOverhead, ReceiveExtraPkt, SendPrelimPkt,
      -- StartCall, StartSignal, StubPkt, UnexportInterface]--,
  LupineRuntime --USING SOME OF [BindingError, CheckPktLength, CopyFromPkt,
      -- CopyFromMultiplePkts, CopyToPkt, CopyToMultiplePkts, defaultZones,
      -- DispatchingError, FinishThisPkt, ListHeader, MarshalingError,
      -- MarshalingExprError, MarshalAtom, MarshalRope, NilHeader, ProtocolError,
      -- RopeHeader, RpcPktDoubleWord, RuntimeError, SequenceHeader, SHORT,
      -- StartNextPkt, StringHeader, StubPktDoubleWord, TranslationError,
      -- UnmarshalingError, UnmarshalingExprError, UnmarshalAtom, UnmarshalRope,
      -- WordsForChars]--,
  Atom --USING SOME OF [GetPName, MakeAtom]--,
  Rope --USING SOME OF [InlineFlatten, Length, NewText, Text]--;


AlpineFileRpcServerImpl: MONITOR
  IMPORTS AlpineFile, RpcPrivate: RPCLupine, Lupine: LupineRuntime,
      Atom, Rope
  EXPORTS AlpineFileRpcControl
  SHARES  AlpineFile, AlpineFileRpcControl, Rope
  = BEGIN OPEN AlpineFile, RpcControl: AlpineFileRpcControl, RpcPublic:
      RPC;


-- Standard remote binding routines.

  bound: BOOLEAN ← FALSE;
  myInterface: RpcPrivate.ExportHandle;
  paramZones: RpcPublic.Zones ← RpcPublic.standardZones;

  ExportInterface: PUBLIC ENTRY SAFE PROCEDURE [
        interfaceName: RpcPublic.InterfaceName,
        user: RpcPublic.Principal,
        password: RpcPublic.EncryptionKey,
        parameterStorage: RpcPublic.Zones ] =
    TRUSTED BEGIN ENABLE UNWIND => NULL;
    IsNull: PROCEDURE [string: Rope.ROPE] RETURNS [BOOLEAN] =
      INLINE {RETURN[string.Length[] = 0]};
    IF bound THEN Lupine.BindingError;
    myInterface ← RpcPrivate.ExportInterface [
      interface: [
        type: IF ~IsNull[interfaceName.type]
          THEN interfaceName.type ELSE "AlpineFile~257#330#25514770454",
        instance: interfaceName.instance,
        version: interfaceName.version ],
      user: user,  password: password,
      dispatcher: ServerDispatcher,
      localOnly: RpcControl.InterMdsCallsOnly,
      stubProtocol: RpcControl.LupineProtocolVersion ];
    paramZones ← [
      gc: IF parameterStorage.gc # NIL
        THEN parameterStorage.gc ELSE Lupine.defaultZones.gc,
      heap: IF parameterStorage.heap # NIL
        THEN parameterStorage.heap ELSE Lupine.defaultZones.heap,
      mds: IF parameterStorage.mds # NIL
        THEN parameterStorage.mds ELSE Lupine.defaultZones.mds ];
    bound ← TRUE;
    END;

  UnexportInterface: PUBLIC ENTRY SAFE PROCEDURE =
    TRUSTED BEGIN ENABLE UNWIND => NULL;
    IF ~bound THEN Lupine.BindingError;
    myInterface ← RpcPrivate.UnexportInterface[myInterface];
    paramZones ← RpcPublic.standardZones;
    bound ← FALSE;
    END;


-- Public procedure dispatcher and public signal and error catcher.

  ServerDispatcher: --PROCEDURE [pkt: RPCPkt, callLength: DataLength,
      -- lastPkt: BOOLEAN, localConversation: Conversation] RETURNS [returnLength:
      -- DataLength]-- RpcPrivate.Dispatcher =
    BEGIN

    -- Catch public signals.

      ENABLE BEGIN

      AccessFailed --ERROR [missingAccess: AlpineEnvironment.NeededAccess]--
          =>
        BEGIN
        ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
            transferIndex (0): RpcControl.SignalIndex ← AccessFailed, missingAccess
            (1): AlpineEnvironment.NeededAccess];
        argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
        pktLength: RpcPrivate.DataLength ← 2;
        lastPkt: BOOLEAN;
        RpcPrivate.StartSignal[signalPkt: pkt];
        argPkt↑ ← [missingAccess: missingAccess];
        [returnLength: , lastPkt: lastPkt] ←
          RpcPrivate.Call[ pkt: pkt, callLength: pktLength,
              maxReturnLength: 0];
        Lupine.RuntimeError;  -- Impossible to RESUME an ERROR.
        END;  -- AccessFailed.

      LockFailed --ERROR [why: AlpineEnvironment.LockFailure]-- =>
        BEGIN
        ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
            transferIndex (0): RpcControl.SignalIndex ← LockFailed, why
            (1): AlpineEnvironment.LockFailure];
        argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
        pktLength: RpcPrivate.DataLength ← 2;
        lastPkt: BOOLEAN;
        RpcPrivate.StartSignal[signalPkt: pkt];
        argPkt↑ ← [why: why];
        [returnLength: , lastPkt: lastPkt] ←
          RpcPrivate.Call[ pkt: pkt, callLength: pktLength,
              maxReturnLength: 0];
        Lupine.RuntimeError;  -- Impossible to RESUME an ERROR.
        END;  -- LockFailed.

      OperationFailed --ERROR [why: AlpineEnvironment.OperationFailure]--
          =>
        BEGIN
        ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
            transferIndex (0): RpcControl.SignalIndex ← OperationFailed,
            why (1): AlpineEnvironment.OperationFailure];
        argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
        pktLength: RpcPrivate.DataLength ← 2;
        lastPkt: BOOLEAN;
        RpcPrivate.StartSignal[signalPkt: pkt];
        argPkt↑ ← [why: why];
        [returnLength: , lastPkt: lastPkt] ←
          RpcPrivate.Call[ pkt: pkt, callLength: pktLength,
              maxReturnLength: 0];
        Lupine.RuntimeError;  -- Impossible to RESUME an ERROR.
        END;  -- OperationFailed.

      StaticallyInvalid --ERROR-- =>
        BEGIN
        ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
            transferIndex (0): RpcControl.SignalIndex ← StaticallyInvalid];
        argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
        pktLength: RpcPrivate.DataLength ← 1;
        lastPkt: BOOLEAN;
        RpcPrivate.StartSignal[signalPkt: pkt];
        argPkt.transferIndex ← StaticallyInvalid;
        [returnLength: , lastPkt: lastPkt] ←
          RpcPrivate.Call[ pkt: pkt, callLength: pktLength,
              maxReturnLength: 0];
        Lupine.RuntimeError;  -- Impossible to RESUME an ERROR.
        END;  -- StaticallyInvalid.

      Unknown --ERROR [what: AlpineEnvironment.UnknownType]-- =>
        BEGIN
        ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
            transferIndex (0): RpcControl.SignalIndex ← Unknown, what (1):
            AlpineEnvironment.UnknownType];
        argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
        pktLength: RpcPrivate.DataLength ← 2;
        lastPkt: BOOLEAN;
        RpcPrivate.StartSignal[signalPkt: pkt];
        argPkt↑ ← [what: what];
        [returnLength: , lastPkt: lastPkt] ←
          RpcPrivate.Call[ pkt: pkt, callLength: pktLength,
              maxReturnLength: 0];
        Lupine.RuntimeError;  -- Impossible to RESUME an ERROR.
        END;  -- Unknown.

      PossiblyDamaged --SIGNAL-- =>
        BEGIN
        ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
            transferIndex (0): RpcControl.SignalIndex ← PossiblyDamaged];
        argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
        pktLength: RpcPrivate.DataLength ← 1;
        lastPkt: BOOLEAN;
        RpcPrivate.StartSignal[signalPkt: pkt];
        argPkt.transferIndex ← PossiblyDamaged;
        [returnLength: , lastPkt: lastPkt] ←
          RpcPrivate.Call[ pkt: pkt, callLength: pktLength,
              maxReturnLength: 0];
        Lupine.CheckPktLength[pkt: pkt, pktLength: 0];
        RESUME[];
        END;  -- PossiblyDamaged.

      END;  -- Catch public signals.


    -- Call public procedures (still in dispatcher).

    SELECT LOOPHOLE[pkt.data[0], RpcControl.ProcedureIndex] FROM
      Open => RETURN[
        OpenStub[pkt: pkt, callLength: callLength, lastPkt: lastPkt,
            localConversation: localConversation]];
      Create => RETURN[
        CreateStub[pkt: pkt, callLength: callLength, lastPkt: lastPkt,
            localConversation: localConversation]];
      Close => RETURN[
        CloseStub[pkt: pkt, callLength: callLength, lastPkt: lastPkt,
            localConversation: localConversation]];
      Delete => RETURN[
        DeleteStub[pkt: pkt, callLength: callLength, lastPkt: lastPkt,
            localConversation: localConversation]];
      GetUniversalFile => RETURN[
        GetUniversalFileStub[pkt: pkt, callLength: callLength, lastPkt:
            lastPkt, localConversation: localConversation]];
      GetTransID => RETURN[
        GetTransIDStub[pkt: pkt, callLength: callLength, lastPkt: lastPkt,
            localConversation: localConversation]];
      GetAccessRights => RETURN[
        GetAccessRightsStub[pkt: pkt, callLength: callLength, lastPkt:
            lastPkt, localConversation: localConversation]];
      GetLockOption => RETURN[
        GetLockOptionStub[pkt: pkt, callLength: callLength, lastPkt:
            lastPkt, localConversation: localConversation]];
      SetLockOption => RETURN[
        SetLockOptionStub[pkt: pkt, callLength: callLength, lastPkt:
            lastPkt, localConversation: localConversation]];
      GetRecoveryOption => RETURN[
        GetRecoveryOptionStub[pkt: pkt, callLength: callLength, lastPkt:
            lastPkt, localConversation: localConversation]];
      GetReferencePattern => RETURN[
        GetReferencePatternStub[pkt: pkt, callLength: callLength, lastPkt:
            lastPkt, localConversation: localConversation]];
      SetReferencePattern => RETURN[
        SetReferencePatternStub[pkt: pkt, callLength: callLength, lastPkt:
            lastPkt, localConversation: localConversation]];
      ReadPages => RETURN[
        ReadPagesStub[pkt: pkt, callLength: callLength, lastPkt: lastPkt,
            localConversation: localConversation]];
      WritePages => RETURN[
        WritePagesStub[pkt: pkt, callLength: callLength, lastPkt: lastPkt,
            localConversation: localConversation]];
      LockPages => RETURN[
        LockPagesStub[pkt: pkt, callLength: callLength, lastPkt: lastPkt,
            localConversation: localConversation]];
      UnlockPages => RETURN[
        UnlockPagesStub[pkt: pkt, callLength: callLength, lastPkt:
            lastPkt, localConversation: localConversation]];
      ValidateCachePageLock => RETURN[
        ValidateCachePageLockStub[pkt: pkt, callLength: callLength,
            lastPkt: lastPkt, localConversation: localConversation]];
      ValidateCachePageLocks => RETURN[
        ValidateCachePageLocksStub[pkt: pkt, callLength: callLength,
            lastPkt: lastPkt, localConversation: localConversation]];
      ReadProperties => RETURN[
        ReadPropertiesStub[pkt: pkt, callLength: callLength, lastPkt:
            lastPkt, localConversation: localConversation]];
      WriteProperties => RETURN[
        WritePropertiesStub[pkt: pkt, callLength: callLength, lastPkt:
            lastPkt, localConversation: localConversation]];
      ReadUserProperties => RETURN[
        ReadUserPropertiesStub[pkt: pkt, callLength: callLength, lastPkt:
            lastPkt, localConversation: localConversation]];
      WriteUserProperties => RETURN[
        WriteUserPropertiesStub[pkt: pkt, callLength: callLength, lastPkt:
            lastPkt, localConversation: localConversation]];
      UnlockVersion => RETURN[
        UnlockVersionStub[pkt: pkt, callLength: callLength, lastPkt:
            lastPkt, localConversation: localConversation]];
      IncrementVersion => RETURN[
        IncrementVersionStub[pkt: pkt, callLength: callLength, lastPkt:
            lastPkt, localConversation: localConversation]];
      GetSize => RETURN[
        GetSizeStub[pkt: pkt, callLength: callLength, lastPkt: lastPkt,
            localConversation: localConversation]];
      SetSize => RETURN[
        SetSizeStub[pkt: pkt, callLength: callLength, lastPkt: lastPkt,
            localConversation: localConversation]];
      UnlockFile => RETURN[
        UnlockFileStub[pkt: pkt, callLength: callLength, lastPkt: lastPkt,
            localConversation: localConversation]];
      ENDCASE => RETURN[Lupine.DispatchingError[]];

    END;  -- ServerDispatcher


-- Public procedure dispatcher stubs.

  OpenStub: --PROCEDURE [conversation: Conversation, transID: TransID,
      -- universalFile: UniversalFile, access: AccessRights, lock: LockOption,
      -- recoveryOption: RecoveryOption, referencePattern: ReferencePattern]
    -- RETURNS [openFileID: OpenFileID, fileID: FileID]-- RpcPrivate.Dispatcher
        =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, transID (1): TransID,
        universalFile (10): UniversalFile, access (19): AccessRights, lock
        (20): LockOption, recoveryOption (21): RecoveryOption, referencePattern
        (22): ReferencePattern];
    ResultOverlay: TYPE = MACHINE DEPENDENT RECORD [
        openFileID (0): OpenFileID, fileID (2): FileID];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    resPkt: LONG POINTER TO ResultOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 23;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    [resPkt.openFileID, resPkt.fileID] ←
      Open[localConversation, argPkt.transID, argPkt.universalFile,
          argPkt.access, argPkt.lock, argPkt.recoveryOption, argPkt.referencePattern];
    pktLength ← 6;
    RETURN[returnLength: pktLength];
    END;  -- OpenStub.

  CreateStub: --PROCEDURE [conversation: Conversation, transID: TransID,
      -- volumeID: VolOrVolGroupID, owner: OwnerName, initialSize: PageCount,
      -- recoveryOption: RecoveryOption, referencePattern: ReferencePattern]
    -- RETURNS [openFileID: OpenFileID, universalFile: UniversalFile]--
        RpcPrivate.Dispatcher =
    BEGIN
    owner: OwnerName;
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, transID (1): TransID,
        volumeID (10): VolOrVolGroupID, initialSize (15): PageCount, recoveryOption
        (17): RecoveryOption, referencePattern (18): ReferencePattern];
    ResultOverlay: TYPE = MACHINE DEPENDENT RECORD [
        openFileID (0): OpenFileID, universalFile (2): UniversalFile];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    resPkt: LONG POINTER TO ResultOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 19;
    BEGIN  -- Unmarshal owner: OwnerName from pkt.data[pktLength].
      ropeIsNIL: Lupine.NilHeader;
      ropeIsNIL ← pkt.data[pktLength];  pktLength ← pktLength+1;
      IF ropeIsNIL
        THEN owner ← NIL
        ELSE BEGIN
          ropeLength: Lupine.RopeHeader;
          textRope: Rope.Text;
          ropeLength ← pkt.data[pktLength];  pktLength ← pktLength+1;
          IF ropeLength > RpcPrivate.maxShortStringLength
            THEN Lupine.UnmarshalingError;
          owner ← textRope ← Rope.NewText[size: ropeLength];
          pktLength ← Lupine.CopyFromPkt[pkt: pkt, pktLength: pktLength,
              dataAdr: BASE[DESCRIPTOR[textRope.text]], dataLength: Lupine.WordsForChars[ropeLength],
              alwaysOnePkt: TRUE];
          END;  -- IF ropeIsNIL.
      END;  -- Unmarshal owner.
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    [resPkt.openFileID, resPkt.universalFile] ←
      Create[localConversation, argPkt.transID, argPkt.volumeID, owner,
          argPkt.initialSize, argPkt.recoveryOption, argPkt.referencePattern];
    pktLength ← 11;
    RETURN[returnLength: pktLength];
    END;  -- CreateStub.

  CloseStub: --PROCEDURE [conversation: Conversation, openFileID: OpenFileID]--
      RpcPrivate.Dispatcher =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 3;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    Close[localConversation, argPkt.openFileID];
    pktLength ← 0;
    RETURN[returnLength: pktLength];
    END;  -- CloseStub.

  DeleteStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID]-- RpcPrivate.Dispatcher =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 3;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    Delete[localConversation, argPkt.openFileID];
    pktLength ← 0;
    RETURN[returnLength: pktLength];
    END;  -- DeleteStub.

  GetUniversalFileStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID] RETURNS [universalFile: UniversalFile]-- RpcPrivate.Dispatcher
      =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID];
    ResultOverlay: TYPE = MACHINE DEPENDENT RECORD [
        universalFile (0): UniversalFile];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    resPkt: LONG POINTER TO ResultOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 3;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    [resPkt.universalFile] ← GetUniversalFile[localConversation, argPkt.openFileID];
    pktLength ← 9;
    RETURN[returnLength: pktLength];
    END;  -- GetUniversalFileStub.

  GetTransIDStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID] RETURNS [transID: TransID]-- RpcPrivate.Dispatcher
      =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID];
    ResultOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transID (0): TransID];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    resPkt: LONG POINTER TO ResultOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 3;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    [resPkt.transID] ← GetTransID[localConversation, argPkt.openFileID];
    pktLength ← 9;
    RETURN[returnLength: pktLength];
    END;  -- GetTransIDStub.

  GetAccessRightsStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID] RETURNS [access: AccessRights]-- RpcPrivate.Dispatcher
      =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID];
    ResultOverlay: TYPE = MACHINE DEPENDENT RECORD [
        access (0): AccessRights];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    resPkt: LONG POINTER TO ResultOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 3;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    [resPkt.access] ← GetAccessRights[localConversation, argPkt.openFileID];
    pktLength ← 1;
    RETURN[returnLength: pktLength];
    END;  -- GetAccessRightsStub.

  GetLockOptionStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID] RETURNS [lock: LockOption]-- RpcPrivate.Dispatcher
      =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID];
    ResultOverlay: TYPE = MACHINE DEPENDENT RECORD [
        lock (0): LockOption];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    resPkt: LONG POINTER TO ResultOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 3;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    [resPkt.lock] ← GetLockOption[localConversation, argPkt.openFileID];
    pktLength ← 1;
    RETURN[returnLength: pktLength];
    END;  -- GetLockOptionStub.

  SetLockOptionStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID, lock: LockOption]-- RpcPrivate.Dispatcher =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID,
        lock (3): LockOption];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 4;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    SetLockOption[localConversation, argPkt.openFileID, argPkt.lock];
    pktLength ← 0;
    RETURN[returnLength: pktLength];
    END;  -- SetLockOptionStub.

  GetRecoveryOptionStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID] RETURNS [recoveryOption: RecoveryOption]-- RpcPrivate.Dispatcher
      =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID];
    ResultOverlay: TYPE = MACHINE DEPENDENT RECORD [
        recoveryOption (0): RecoveryOption];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    resPkt: LONG POINTER TO ResultOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 3;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    [resPkt.recoveryOption] ← GetRecoveryOption[localConversation,
        argPkt.openFileID];
    pktLength ← 1;
    RETURN[returnLength: pktLength];
    END;  -- GetRecoveryOptionStub.

  GetReferencePatternStub: --PROCEDURE [conversation: Conversation,
      -- openFileID: OpenFileID] RETURNS [referencePattern: ReferencePattern]--
      RpcPrivate.Dispatcher =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID];
    ResultOverlay: TYPE = MACHINE DEPENDENT RECORD [
        referencePattern (0): ReferencePattern];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    resPkt: LONG POINTER TO ResultOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 3;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    [resPkt.referencePattern] ← GetReferencePattern[localConversation,
        argPkt.openFileID];
    pktLength ← 1;
    RETURN[returnLength: pktLength];
    END;  -- GetReferencePatternStub.

  SetReferencePatternStub: --PROCEDURE [conversation: Conversation,
      -- openFileID: OpenFileID, referencePattern: ReferencePattern]--
      RpcPrivate.Dispatcher =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID,
        referencePattern (3): ReferencePattern];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 4;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    SetReferencePattern[localConversation, argPkt.openFileID, argPkt.referencePattern];
    pktLength ← 0;
    RETURN[returnLength: pktLength];
    END;  -- SetReferencePatternStub.

  ReadPagesStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID, pageRun: PageRun, pageBuffer: RESULTPageBuffer, lock:
      -- LockOption]-- RpcPrivate.Dispatcher =
    BEGIN
    pageBuffer: RESULTPageBuffer;
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID,
        pageRun (3): PageRun, lock (6): LockOption];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 7;
    MaxHeapAllocs: CARDINAL = 1;
    heapAllocVector: ARRAY [1..MaxHeapAllocs] OF LONG POINTER←ALL[NIL];
    BEGIN ENABLE UNWIND => BEGIN  -- Free storage.
        FOR ptr: CARDINAL IN [1..LENGTH[heapAllocVector]] DO
          IF heapAllocVector[ptr] = NIL THEN EXIT;
          paramZones.heap.FREE[@heapAllocVector[ptr]];
          ENDLOOP;
        END;  -- Free storage.
      BEGIN  -- Unmarshal pageBuffer: RESULTPageBuffer from pkt.data[pktLength].
        DescriptorType: TYPE = RECORD [SEQUENCE COMPUTED CARDINAL OF
            WORD];
        descLength: Lupine.SequenceHeader;
        descLength ← Lupine.RpcPktDoubleWord[pkt, pktLength]↑;
        pktLength ← pktLength + 2;
        pageBuffer ← DESCRIPTOR[
          (heapAllocVector[1] ← paramZones.heap.NEW[DescriptorType[Lupine.SHORT[descLength]]]),
          Lupine.SHORT[descLength]];
        NULL;  -- Call by result, use uninitialized descriptor.
        END;  -- Unmarshal pageBuffer.
      Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
      ReadPages[localConversation, argPkt.openFileID, argPkt.pageRun,
          pageBuffer, argPkt.lock];
      pktLength ← 0;
      BEGIN  -- Marshal pageBuffer: RESULTPageBuffer to pkt.data[pktLength].
        IF pktLength+2 > RpcPrivate.maxDataLength
          THEN pktLength ← Lupine.StartNextPkt[pkt: pkt, pktLength:
              pktLength];
        Lupine.RpcPktDoubleWord[pkt, pktLength]↑ ← (IF BASE[pageBuffer]=NIL
            THEN 0 ELSE LENGTH[pageBuffer]);
        pktLength ← pktLength + 2;
        IF BASE[pageBuffer] # NIL THEN
          pktLength ← Lupine.CopyToPkt[pkt: pkt, pktLength: pktLength,
              dataAdr: BASE[pageBuffer], dataLength: SIZE[WORD]*LENGTH[pageBuffer],
              alwaysOnePkt: FALSE];
        END;  -- Marshal pageBuffer.
      END;  -- ENABLE UNWIND => Free storage.
    FOR ptr: CARDINAL IN [1..LENGTH[heapAllocVector]] DO
      IF heapAllocVector[ptr] = NIL THEN EXIT;
      paramZones.heap.FREE[@heapAllocVector[ptr]];
      ENDLOOP;
    RETURN[returnLength: pktLength];
    END;  -- ReadPagesStub.

  WritePagesStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID, pageRun: PageRun, pageBuffer: VALUEPageBuffer, lock:
      -- LockOption]-- RpcPrivate.Dispatcher =
    BEGIN
    openFileID: OpenFileID;
    pageRun: PageRun;
    pageBuffer: VALUEPageBuffer;
    lock: LockOption;
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID,
        pageRun (3): PageRun, lock (6): LockOption];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 7;
    MaxHeapAllocs: CARDINAL = 1;
    heapAllocVector: ARRAY [1..MaxHeapAllocs] OF LONG POINTER←ALL[NIL];
    BEGIN ENABLE UNWIND => BEGIN  -- Free storage.
        FOR ptr: CARDINAL IN [1..LENGTH[heapAllocVector]] DO
          IF heapAllocVector[ptr] = NIL THEN EXIT;
          paramZones.heap.FREE[@heapAllocVector[ptr]];
          ENDLOOP;
        END;  -- Free storage.
      BEGIN  -- OnePkt.
      onePkt: BOOLEAN = lastPkt;
      IF ~onePkt THEN BEGIN  -- Must move statics from pkt now.
        [openFileID: openFileID, pageRun: pageRun, lock: lock] ← argPkt↑;
        END;
      BEGIN  -- Unmarshal pageBuffer: VALUEPageBuffer from pkt.data[pktLength].
        DescriptorType: TYPE = RECORD [SEQUENCE COMPUTED CARDINAL OF
            WORD];
        descLength: Lupine.SequenceHeader;
        IF pktLength+2 > RpcPrivate.maxDataLength
          THEN pktLength ← Lupine.FinishThisPkt[pkt: pkt, pktLength:
              pktLength];
        descLength ← Lupine.RpcPktDoubleWord[pkt, pktLength]↑;
        pktLength ← pktLength + 2;
        pageBuffer ← DESCRIPTOR[
          (heapAllocVector[1] ← paramZones.heap.NEW[DescriptorType[Lupine.SHORT[descLength]]]),
          Lupine.SHORT[descLength]];
        pktLength ← Lupine.CopyFromPkt[pkt: pkt, pktLength: pktLength,
            dataAdr: BASE[pageBuffer], dataLength: SIZE[WORD]*LENGTH[pageBuffer],
            alwaysOnePkt: FALSE];
        END;  -- Unmarshal pageBuffer.
      Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
      IF onePkt
        THEN WritePages[localConversation, argPkt.openFileID, argPkt.pageRun,
            pageBuffer, argPkt.lock]
        ELSE WritePages[localConversation, openFileID, pageRun, pageBuffer,
            lock];
      END;  -- OnePkt.
      pktLength ← 0;
      END;  -- ENABLE UNWIND => Free storage.
    FOR ptr: CARDINAL IN [1..LENGTH[heapAllocVector]] DO
      IF heapAllocVector[ptr] = NIL THEN EXIT;
      paramZones.heap.FREE[@heapAllocVector[ptr]];
      ENDLOOP;
    RETURN[returnLength: pktLength];
    END;  -- WritePagesStub.

  LockPagesStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID, pageRun: PageRun, lock: LockOption]-- RpcPrivate.Dispatcher
      =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID,
        pageRun (3): PageRun, lock (6): LockOption];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 7;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    LockPages[localConversation, argPkt.openFileID, argPkt.pageRun,
        argPkt.lock];
    pktLength ← 0;
    RETURN[returnLength: pktLength];
    END;  -- LockPagesStub.

  UnlockPagesStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID, pageRun: PageRun, retainCacheLocks: BOOLEAN]-- RpcPrivate.Dispatcher
      =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID,
        pageRun (3): PageRun, retainCacheLocks (6): BOOLEAN];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 7;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    UnlockPages[localConversation, argPkt.openFileID, argPkt.pageRun,
        argPkt.retainCacheLocks];
    pktLength ← 0;
    RETURN[returnLength: pktLength];
    END;  -- UnlockPagesStub.

  ValidateCachePageLockStub: --PROCEDURE [conversation: Conversation,
      -- lock: CachePageLockConversion] RETURNS [success: BOOLEAN]-- RpcPrivate.Dispatcher
      =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, lock (1): CachePageLockConversion];
    ResultOverlay: TYPE = MACHINE DEPENDENT RECORD [
        success (0): BOOLEAN];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    resPkt: LONG POINTER TO ResultOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 15;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    [resPkt.success] ← ValidateCachePageLock[localConversation, argPkt.lock];
    pktLength ← 1;
    RETURN[returnLength: pktLength];
    END;  -- ValidateCachePageLockStub.

  ValidateCachePageLocksStub: --PROCEDURE [conversation: Conversation,
      -- locks: CachePageLockConversions] RETURNS [locksGranted: LIST OF
      -- CachePageLockConversion, locksNotGranted: LIST OF CachePageLockConversion]--
      RpcPrivate.Dispatcher =
    BEGIN
    locks: CachePageLockConversions;
    locksGranted: LIST OF CachePageLockConversion;
    locksNotGranted: LIST OF CachePageLockConversion;
    pktLength: RpcPrivate.DataLength ← 1;
    BEGIN  -- Unmarshal locks: CachePageLockConversions from pkt.data[pktLength].
      [locks, pktLength] ← UnmarshalCachePageLockConversions[pkt, pktLength];
      END;  -- Unmarshal locks.
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    [locksGranted, locksNotGranted] ←
      ValidateCachePageLocks[localConversation, locks];
    pktLength ← 0;
    BEGIN  -- Marshal locksGranted: LIST OF CachePageLockConversion
        -- to pkt.data[pktLength].
      thisNode1: LIST OF CachePageLockConversion;
      listLength: Lupine.ListHeader ← 0;
      FOR thisNode1 ← locksGranted, thisNode1.rest UNTIL thisNode1
          = NIL DO
        listLength ← listLength + 1;  ENDLOOP;
      IF pktLength+2 > RpcPrivate.maxDataLength
        THEN pktLength ← Lupine.StartNextPkt[pkt: pkt, pktLength: pktLength];
      Lupine.RpcPktDoubleWord[pkt, pktLength]↑ ← listLength;
      pktLength ← pktLength + 2;
      FOR thisNode1 ← locksGranted, thisNode1.rest UNTIL thisNode1
          = NIL DO
        BEGIN  -- Marshal thisNode1.first: CachePageLockConversion
            -- to pkt.data[pktLength].
          pktLength ← Lupine.CopyToPkt[pkt: pkt, pktLength: pktLength,
              dataAdr: @thisNode1.first, dataLength: SIZE[CachePageLockConversion],
              alwaysOnePkt: FALSE];
          END;  -- Marshal thisNode1.first.
        ENDLOOP;  -- FOR thisNode1.
      END;  -- Marshal locksGranted.
    BEGIN  -- Marshal locksNotGranted: LIST OF CachePageLockConversion
        -- to pkt.data[pktLength].
      thisNode1: LIST OF CachePageLockConversion;
      listLength: Lupine.ListHeader ← 0;
      FOR thisNode1 ← locksNotGranted, thisNode1.rest UNTIL thisNode1
          = NIL DO
        listLength ← listLength + 1;  ENDLOOP;
      IF pktLength+2 > RpcPrivate.maxDataLength
        THEN pktLength ← Lupine.StartNextPkt[pkt: pkt, pktLength: pktLength];
      Lupine.RpcPktDoubleWord[pkt, pktLength]↑ ← listLength;
      pktLength ← pktLength + 2;
      FOR thisNode1 ← locksNotGranted, thisNode1.rest UNTIL thisNode1
          = NIL DO
        BEGIN  -- Marshal thisNode1.first: CachePageLockConversion
            -- to pkt.data[pktLength].
          pktLength ← Lupine.CopyToPkt[pkt: pkt, pktLength: pktLength,
              dataAdr: @thisNode1.first, dataLength: SIZE[CachePageLockConversion],
              alwaysOnePkt: FALSE];
          END;  -- Marshal thisNode1.first.
        ENDLOOP;  -- FOR thisNode1.
      END;  -- Marshal locksNotGranted.
    RETURN[returnLength: pktLength];
    END;  -- ValidateCachePageLocksStub.

  ReadPropertiesStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID, desiredProperties: PropertySet, lock: LockOption]
    -- RETURNS [properties: LIST OF PropertyValuePair]-- RpcPrivate.Dispatcher
        =
    BEGIN
    properties: LIST OF PropertyValuePair;
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID,
        desiredProperties (3): PropertySet, lock (4): LockOption];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 5;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    [properties] ← ReadProperties[localConversation, argPkt.openFileID,
        argPkt.desiredProperties, argPkt.lock];
    pktLength ← 0;
    BEGIN  -- Marshal properties: LIST OF PropertyValuePair to pkt.data[pktLength].
      thisNode1: LIST OF PropertyValuePair;
      listLength: Lupine.ListHeader ← 0;
      FOR thisNode1 ← properties, thisNode1.rest UNTIL thisNode1 =
          NIL DO
        listLength ← listLength + 1;  ENDLOOP;
      IF pktLength+2 > RpcPrivate.maxDataLength
        THEN pktLength ← Lupine.StartNextPkt[pkt: pkt, pktLength: pktLength];
      Lupine.RpcPktDoubleWord[pkt, pktLength]↑ ← listLength;
      pktLength ← pktLength + 2;
      FOR thisNode1 ← properties, thisNode1.rest UNTIL thisNode1 =
          NIL DO
        BEGIN  -- Marshal thisNode1.first: PropertyValuePair to pkt.data[pktLength].
          pktLength ← Lupine.CopyToPkt[pkt: pkt, pktLength: pktLength,
              dataAdr: @thisNode1.first, dataLength: SIZE[PropertyValuePair],
              alwaysOnePkt: FALSE];
          BEGIN OPEN record: thisNode1.first;
          WITH variant: record SELECT FROM
            modifyAccess =>
              BEGIN  -- Marshal variant: RECORD [modifyAccess: AccessList]
                  -- to pkt.data[pktLength].
                BEGIN OPEN record: variant;
                BEGIN  -- Marshal record.modifyAccess: AccessList to
                    -- pkt.data[pktLength].
                  thisNode5: AccessList;
                  listLength: Lupine.ListHeader ← 0;
                  FOR thisNode5 ← record.modifyAccess, thisNode5.rest
                      UNTIL thisNode5 = NIL DO
                    listLength ← listLength + 1;  ENDLOOP;
                  IF pktLength+2 > RpcPrivate.maxDataLength
                    THEN pktLength ← Lupine.StartNextPkt[pkt: pkt,
                        pktLength: pktLength];
                  Lupine.RpcPktDoubleWord[pkt, pktLength]↑ ← listLength;
                  pktLength ← pktLength + 2;
                  FOR thisNode5 ← record.modifyAccess, thisNode5.rest
                      UNTIL thisNode5 = NIL DO
                    BEGIN  -- Marshal thisNode5.first: RName to pkt.data[pktLength].
                      IF pktLength+2 > RpcPrivate.maxDataLength
                        THEN pktLength ← Lupine.StartNextPkt[pkt: pkt,
                            pktLength: pktLength];
                      pkt.data[pktLength] ← thisNode5.first=NIL;  pktLength
                          ← pktLength+1;
                      IF thisNode5.first # NIL
                        THEN BEGIN
                          textRope: Rope.Text = Rope.InlineFlatten[r:
                              thisNode5.first];
                          IF textRope.length > RpcPrivate.maxShortStringLength
                            THEN Lupine.MarshalingError;
                          pkt.data[pktLength] ← textRope.length;  pktLength
                              ← pktLength+1;
                          pktLength ← Lupine.CopyToPkt[pkt: pkt, pktLength:
                              pktLength, dataAdr: BASE[DESCRIPTOR[textRope.text]],
                              dataLength: Lupine.WordsForChars[textRope.length],
                              alwaysOnePkt: FALSE];
                          END;  -- IF thisNode5.first # NIL.
                      END;  -- Marshal thisNode5.first.
                    ENDLOOP;  -- FOR thisNode5.
                  END;  -- Marshal record.modifyAccess.
                END;  -- OPEN record: variant.
                END;  -- Marshal variant.
            owner =>
              BEGIN  -- Marshal variant: RECORD [owner: OwnerName]
                  -- to pkt.data[pktLength].
                BEGIN OPEN record: variant;
                BEGIN  -- Marshal record.owner: OwnerName to pkt.data[pktLength].
                  IF pktLength+2 > RpcPrivate.maxDataLength
                    THEN pktLength ← Lupine.StartNextPkt[pkt: pkt,
                        pktLength: pktLength];
                  pkt.data[pktLength] ← record.owner=NIL;  pktLength
                      ← pktLength+1;
                  IF record.owner # NIL
                    THEN BEGIN
                      textRope: Rope.Text = Rope.InlineFlatten[r: record.owner];
                      IF textRope.length > RpcPrivate.maxShortStringLength
                        THEN Lupine.MarshalingError;
                      pkt.data[pktLength] ← textRope.length;  pktLength
                          ← pktLength+1;
                      pktLength ← Lupine.CopyToPkt[pkt: pkt, pktLength:
                          pktLength, dataAdr: BASE[DESCRIPTOR[textRope.text]],
                          dataLength: Lupine.WordsForChars[textRope.length],
                          alwaysOnePkt: FALSE];
                      END;  -- IF record.owner # NIL.
                  END;  -- Marshal record.owner.
                END;  -- OPEN record: variant.
                END;  -- Marshal variant.
            readAccess =>
              BEGIN  -- Marshal variant: RECORD [readAccess: AccessList]
                  -- to pkt.data[pktLength].
                BEGIN OPEN record: variant;
                BEGIN  -- Marshal record.readAccess: AccessList to
                    -- pkt.data[pktLength].
                  thisNode5: AccessList;
                  listLength: Lupine.ListHeader ← 0;
                  FOR thisNode5 ← record.readAccess, thisNode5.rest
                      UNTIL thisNode5 = NIL DO
                    listLength ← listLength + 1;  ENDLOOP;
                  IF pktLength+2 > RpcPrivate.maxDataLength
                    THEN pktLength ← Lupine.StartNextPkt[pkt: pkt,
                        pktLength: pktLength];
                  Lupine.RpcPktDoubleWord[pkt, pktLength]↑ ← listLength;
                  pktLength ← pktLength + 2;
                  FOR thisNode5 ← record.readAccess, thisNode5.rest
                      UNTIL thisNode5 = NIL DO
                    BEGIN  -- Marshal thisNode5.first: RName to pkt.data[pktLength].
                      IF pktLength+2 > RpcPrivate.maxDataLength
                        THEN pktLength ← Lupine.StartNextPkt[pkt: pkt,
                            pktLength: pktLength];
                      pkt.data[pktLength] ← thisNode5.first=NIL;  pktLength
                          ← pktLength+1;
                      IF thisNode5.first # NIL
                        THEN BEGIN
                          textRope: Rope.Text = Rope.InlineFlatten[r:
                              thisNode5.first];
                          IF textRope.length > RpcPrivate.maxShortStringLength
                            THEN Lupine.MarshalingError;
                          pkt.data[pktLength] ← textRope.length;  pktLength
                              ← pktLength+1;
                          pktLength ← Lupine.CopyToPkt[pkt: pkt, pktLength:
                              pktLength, dataAdr: BASE[DESCRIPTOR[textRope.text]],
                              dataLength: Lupine.WordsForChars[textRope.length],
                              alwaysOnePkt: FALSE];
                          END;  -- IF thisNode5.first # NIL.
                      END;  -- Marshal thisNode5.first.
                    ENDLOOP;  -- FOR thisNode5.
                  END;  -- Marshal record.readAccess.
                END;  -- OPEN record: variant.
                END;  -- Marshal variant.
            stringName =>
              BEGIN  -- Marshal variant: RECORD [stringName: Rope.ROPE]
                  -- to pkt.data[pktLength].
                BEGIN OPEN record: variant;
                BEGIN  -- Marshal record.stringName: Rope.ROPE to pkt.data[pktLength].
                  IF pktLength+2 > RpcPrivate.maxDataLength
                    THEN pktLength ← Lupine.StartNextPkt[pkt: pkt,
                        pktLength: pktLength];
                  pkt.data[pktLength] ← record.stringName=NIL;  pktLength
                      ← pktLength+1;
                  IF record.stringName # NIL
                    THEN BEGIN
                      textRope: Rope.Text = Rope.InlineFlatten[r: record.stringName];
                      pkt.data[pktLength] ← textRope.length;  pktLength
                          ← pktLength+1;
                      pktLength ← Lupine.CopyToPkt[pkt: pkt, pktLength:
                          pktLength, dataAdr: BASE[DESCRIPTOR[textRope.text]],
                          dataLength: Lupine.WordsForChars[textRope.length],
                          alwaysOnePkt: FALSE];
                      END;  -- IF record.stringName # NIL.
                  END;  -- Marshal record.stringName.
                END;  -- OPEN record: variant.
                END;  -- Marshal variant.
            ENDCASE => NULL;  -- WITH variant: record.
          END;  -- OPEN record: thisNode1.first.
          END;  -- Marshal thisNode1.first.
        ENDLOOP;  -- FOR thisNode1.
      END;  -- Marshal properties.
    RETURN[returnLength: pktLength];
    END;  -- ReadPropertiesStub.

  WritePropertiesStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID, properties: LIST OF PropertyValuePair, lock: LockOption]--
      RpcPrivate.Dispatcher =
    BEGIN
    openFileID: OpenFileID;
    properties: LIST OF PropertyValuePair;
    lock: LockOption;
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID,
        lock (3): LockOption];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 4;
    BEGIN  -- OnePkt.
    onePkt: BOOLEAN = lastPkt;
    IF ~onePkt THEN BEGIN  -- Must move statics from pkt now.
      [openFileID: openFileID, lock: lock] ← argPkt↑;
      END;
    BEGIN  -- Unmarshal properties: LIST OF PropertyValuePair from
        -- pkt.data[pktLength].
      lastNode: LIST OF PropertyValuePair ← (properties ← NIL);
      listLength: Lupine.ListHeader;
      IF pktLength+2 > RpcPrivate.maxDataLength
        THEN pktLength ← Lupine.FinishThisPkt[pkt: pkt, pktLength:
            pktLength];
      listLength ← Lupine.RpcPktDoubleWord[pkt, pktLength]↑;
      pktLength ← pktLength + 2;
      WHILE listLength > 0 DO
        thisNode1: LIST OF PropertyValuePair = paramZones.gc.CONS[--DefaultValue--,NIL];
        BEGIN  -- Unmarshal thisNode1.first: PropertyValuePair from
            -- pkt.data[pktLength].
          pktLength ← Lupine.CopyFromPkt[pkt: pkt, pktLength: pktLength,
              dataAdr: @thisNode1.first, dataLength: SIZE[PropertyValuePair],
              alwaysOnePkt: FALSE];
          -- Restore garbled REFs to NIL following copy.
          BEGIN OPEN record: thisNode1.first;
          WITH variant: record SELECT FROM
            modifyAccess =>
              BEGIN OPEN record: variant;
              LOOPHOLE[record.modifyAccess, LONG POINTER] ← NIL;
              END;  -- OPEN record: variant.
            owner =>
              BEGIN OPEN record: variant;
              LOOPHOLE[record.owner, LONG POINTER] ← NIL;
              END;  -- OPEN record: variant.
            readAccess =>
              BEGIN OPEN record: variant;
              LOOPHOLE[record.readAccess, LONG POINTER] ← NIL;
              END;  -- OPEN record: variant.
            stringName =>
              BEGIN OPEN record: variant;
              LOOPHOLE[record.stringName, LONG POINTER] ← NIL;
              END;  -- OPEN record: variant.
            ENDCASE => NULL;  -- WITH variant: record.
          END;  -- OPEN record: thisNode1.first.
          BEGIN OPEN record: thisNode1.first;
          WITH variant: record SELECT FROM
            modifyAccess =>
              BEGIN  -- Unmarshal variant: RECORD [modifyAccess: AccessList]
                  -- from pkt.data[pktLength].
                BEGIN OPEN record: variant;
                BEGIN  -- Unmarshal record.modifyAccess: AccessList
                    -- from pkt.data[pktLength].
                  lastNode: AccessList ← (record.modifyAccess ← NIL);
                  listLength: Lupine.ListHeader;
                  IF pktLength+2 > RpcPrivate.maxDataLength
                    THEN pktLength ← Lupine.FinishThisPkt[pkt: pkt,
                        pktLength: pktLength];
                  listLength ← Lupine.RpcPktDoubleWord[pkt, pktLength]↑;
                  pktLength ← pktLength + 2;
                  WHILE listLength > 0 DO
                    thisNode5: AccessList = paramZones.gc.CONS[--DefaultValue--,NIL];
                    BEGIN  -- Unmarshal thisNode5.first: RName from
                        -- pkt.data[pktLength].
                      ropeIsNIL: Lupine.NilHeader;
                      IF pktLength+2 > RpcPrivate.maxDataLength
                        THEN pktLength ← Lupine.FinishThisPkt[pkt:
                            pkt, pktLength: pktLength];
                      ropeIsNIL ← pkt.data[pktLength];  pktLength ←
                          pktLength+1;
                      IF ropeIsNIL
                        THEN thisNode5.first ← NIL
                        ELSE BEGIN
                          ropeLength: Lupine.RopeHeader;
                          textRope: Rope.Text;
                          ropeLength ← pkt.data[pktLength];  pktLength
                              ← pktLength+1;
                          IF ropeLength > RpcPrivate.maxShortStringLength
                            THEN Lupine.UnmarshalingError;
                          thisNode5.first ← textRope ← Rope.NewText[size:
                              ropeLength];
                          pktLength ← Lupine.CopyFromPkt[pkt: pkt,
                              pktLength: pktLength, dataAdr: BASE[DESCRIPTOR[textRope.text]],
                              dataLength: Lupine.WordsForChars[ropeLength],
                              alwaysOnePkt: FALSE];
                          END;  -- IF ropeIsNIL.
                      END;  -- Unmarshal thisNode5.first.
                    IF lastNode # NIL
                      THEN lastNode ← (lastNode.rest ← thisNode5)
                      ELSE lastNode ← (record.modifyAccess ← thisNode5);
                    listLength ← listLength - 1;
                    ENDLOOP;  -- WHILE listLength > 0.
                  END;  -- Unmarshal record.modifyAccess.
                END;  -- OPEN record: variant.
                END;  -- Unmarshal variant.
            owner =>
              BEGIN  -- Unmarshal variant: RECORD [owner: OwnerName]
                  -- from pkt.data[pktLength].
                BEGIN OPEN record: variant;
                BEGIN  -- Unmarshal record.owner: OwnerName from pkt.data[pktLength].
                  ropeIsNIL: Lupine.NilHeader;
                  IF pktLength+2 > RpcPrivate.maxDataLength
                    THEN pktLength ← Lupine.FinishThisPkt[pkt: pkt,
                        pktLength: pktLength];
                  ropeIsNIL ← pkt.data[pktLength];  pktLength ← pktLength+1;
                  IF ropeIsNIL
                    THEN record.owner ← NIL
                    ELSE BEGIN
                      ropeLength: Lupine.RopeHeader;
                      textRope: Rope.Text;
                      ropeLength ← pkt.data[pktLength];  pktLength
                          ← pktLength+1;
                      IF ropeLength > RpcPrivate.maxShortStringLength
                        THEN Lupine.UnmarshalingError;
                      record.owner ← textRope ← Rope.NewText[size:
                          ropeLength];
                      pktLength ← Lupine.CopyFromPkt[pkt: pkt, pktLength:
                          pktLength, dataAdr: BASE[DESCRIPTOR[textRope.text]],
                          dataLength: Lupine.WordsForChars[ropeLength],
                          alwaysOnePkt: FALSE];
                      END;  -- IF ropeIsNIL.
                  END;  -- Unmarshal record.owner.
                END;  -- OPEN record: variant.
                END;  -- Unmarshal variant.
            readAccess =>
              BEGIN  -- Unmarshal variant: RECORD [readAccess: AccessList]
                  -- from pkt.data[pktLength].
                BEGIN OPEN record: variant;
                BEGIN  -- Unmarshal record.readAccess: AccessList from
                    -- pkt.data[pktLength].
                  lastNode: AccessList ← (record.readAccess ← NIL);
                  listLength: Lupine.ListHeader;
                  IF pktLength+2 > RpcPrivate.maxDataLength
                    THEN pktLength ← Lupine.FinishThisPkt[pkt: pkt,
                        pktLength: pktLength];
                  listLength ← Lupine.RpcPktDoubleWord[pkt, pktLength]↑;
                  pktLength ← pktLength + 2;
                  WHILE listLength > 0 DO
                    thisNode5: AccessList = paramZones.gc.CONS[--DefaultValue--,NIL];
                    BEGIN  -- Unmarshal thisNode5.first: RName from
                        -- pkt.data[pktLength].
                      ropeIsNIL: Lupine.NilHeader;
                      IF pktLength+2 > RpcPrivate.maxDataLength
                        THEN pktLength ← Lupine.FinishThisPkt[pkt:
                            pkt, pktLength: pktLength];
                      ropeIsNIL ← pkt.data[pktLength];  pktLength ←
                          pktLength+1;
                      IF ropeIsNIL
                        THEN thisNode5.first ← NIL
                        ELSE BEGIN
                          ropeLength: Lupine.RopeHeader;
                          textRope: Rope.Text;
                          ropeLength ← pkt.data[pktLength];  pktLength
                              ← pktLength+1;
                          IF ropeLength > RpcPrivate.maxShortStringLength
                            THEN Lupine.UnmarshalingError;
                          thisNode5.first ← textRope ← Rope.NewText[size:
                              ropeLength];
                          pktLength ← Lupine.CopyFromPkt[pkt: pkt,
                              pktLength: pktLength, dataAdr: BASE[DESCRIPTOR[textRope.text]],
                              dataLength: Lupine.WordsForChars[ropeLength],
                              alwaysOnePkt: FALSE];
                          END;  -- IF ropeIsNIL.
                      END;  -- Unmarshal thisNode5.first.
                    IF lastNode # NIL
                      THEN lastNode ← (lastNode.rest ← thisNode5)
                      ELSE lastNode ← (record.readAccess ← thisNode5);
                    listLength ← listLength - 1;
                    ENDLOOP;  -- WHILE listLength > 0.
                  END;  -- Unmarshal record.readAccess.
                END;  -- OPEN record: variant.
                END;  -- Unmarshal variant.
            stringName =>
              BEGIN  -- Unmarshal variant: RECORD [stringName: Rope.ROPE]
                  -- from pkt.data[pktLength].
                BEGIN OPEN record: variant;
                BEGIN  -- Unmarshal record.stringName: Rope.ROPE from
                    -- pkt.data[pktLength].
                  ropeIsNIL: Lupine.NilHeader;
                  IF pktLength+2 > RpcPrivate.maxDataLength
                    THEN pktLength ← Lupine.FinishThisPkt[pkt: pkt,
                        pktLength: pktLength];
                  ropeIsNIL ← pkt.data[pktLength];  pktLength ← pktLength+1;
                  IF ropeIsNIL
                    THEN record.stringName ← NIL
                    ELSE BEGIN
                      ropeLength: Lupine.RopeHeader;
                      textRope: Rope.Text;
                      ropeLength ← pkt.data[pktLength];  pktLength
                          ← pktLength+1;
                      IF ropeLength > LAST[NAT]
                        THEN Lupine.UnmarshalingError;
                      record.stringName ← textRope ← Rope.NewText[size:
                          ropeLength];
                      pktLength ← Lupine.CopyFromPkt[pkt: pkt, pktLength:
                          pktLength, dataAdr: BASE[DESCRIPTOR[textRope.text]],
                          dataLength: Lupine.WordsForChars[ropeLength],
                          alwaysOnePkt: FALSE];
                      END;  -- IF ropeIsNIL.
                  END;  -- Unmarshal record.stringName.
                END;  -- OPEN record: variant.
                END;  -- Unmarshal variant.
            ENDCASE => NULL;  -- WITH variant: record.
          END;  -- OPEN record: thisNode1.first.
          END;  -- Unmarshal thisNode1.first.
        IF lastNode # NIL
          THEN lastNode ← (lastNode.rest ← thisNode1)
          ELSE lastNode ← (properties ← thisNode1);
        listLength ← listLength - 1;
        ENDLOOP;  -- WHILE listLength > 0.
      END;  -- Unmarshal properties.
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    IF onePkt
      THEN WriteProperties[localConversation, argPkt.openFileID, properties,
          argPkt.lock]
      ELSE WriteProperties[localConversation, openFileID, properties,
          lock];
    END;  -- OnePkt.
    pktLength ← 0;
    RETURN[returnLength: pktLength];
    END;  -- WritePropertiesStub.

  ReadUserPropertiesStub: --PROCEDURE [conversation: Conversation,
      -- openFileID: OpenFileID, desiredProperties: UserProperties, lock:
      -- LockOption]
    -- RETURNS [properties: UserPropertyValuePairs]-- RpcPrivate.Dispatcher
        =
    BEGIN
    openFileID: OpenFileID;
    desiredProperties: UserProperties;
    lock: LockOption;
    properties: UserPropertyValuePairs;
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID,
        lock (3): LockOption];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 4;
    BEGIN  -- OnePkt.
    onePkt: BOOLEAN = lastPkt;
    IF ~onePkt THEN BEGIN  -- Must move statics from pkt now.
      [openFileID: openFileID, lock: lock] ← argPkt↑;
      END;
    BEGIN  -- Unmarshal desiredProperties: UserProperties from pkt.data[pktLength].
      lastNode: UserProperties ← (desiredProperties ← NIL);
      listLength: Lupine.ListHeader;
      IF pktLength+2 > RpcPrivate.maxDataLength
        THEN pktLength ← Lupine.FinishThisPkt[pkt: pkt, pktLength:
            pktLength];
      listLength ← Lupine.RpcPktDoubleWord[pkt, pktLength]↑;
      pktLength ← pktLength + 2;
      WHILE listLength > 0 DO
        thisNode1: UserProperties = paramZones.gc.CONS[--DefaultValue--,NIL];
        BEGIN  -- Unmarshal thisNode1.first: AlpineEnvironment.UserProperty
            -- from pkt.data[pktLength].
          ropeIsNIL: Lupine.NilHeader;
          IF pktLength+2 > RpcPrivate.maxDataLength
            THEN pktLength ← Lupine.FinishThisPkt[pkt: pkt, pktLength:
                pktLength];
          ropeIsNIL ← pkt.data[pktLength];  pktLength ← pktLength+1;
          IF ropeIsNIL
            THEN thisNode1.first ← NIL
            ELSE BEGIN
              ropeLength: Lupine.RopeHeader;
              textRope: Rope.Text;
              ropeLength ← pkt.data[pktLength];  pktLength ← pktLength+1;
              IF ropeLength > LAST[NAT]
                THEN Lupine.UnmarshalingError;
              thisNode1.first ← textRope ← Rope.NewText[size: ropeLength];
              pktLength ← Lupine.CopyFromPkt[pkt: pkt, pktLength: pktLength,
                  dataAdr: BASE[DESCRIPTOR[textRope.text]], dataLength:
                  Lupine.WordsForChars[ropeLength], alwaysOnePkt: FALSE];
              END;  -- IF ropeIsNIL.
          END;  -- Unmarshal thisNode1.first.
        IF lastNode # NIL
          THEN lastNode ← (lastNode.rest ← thisNode1)
          ELSE lastNode ← (desiredProperties ← thisNode1);
        listLength ← listLength - 1;
        ENDLOOP;  -- WHILE listLength > 0.
      END;  -- Unmarshal desiredProperties.
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    IF onePkt
      THEN [properties] ← ReadUserProperties[localConversation, argPkt.openFileID,
          desiredProperties, argPkt.lock]
      ELSE [properties] ← ReadUserProperties[localConversation, openFileID,
          desiredProperties, lock];
    END;  -- OnePkt.
    pktLength ← 0;
    BEGIN  -- Marshal properties: UserPropertyValuePairs to pkt.data[pktLength].
      thisNode1: UserPropertyValuePairs;
      listLength: Lupine.ListHeader ← 0;
      FOR thisNode1 ← properties, thisNode1.rest UNTIL thisNode1 =
          NIL DO
        listLength ← listLength + 1;  ENDLOOP;
      IF pktLength+2 > RpcPrivate.maxDataLength
        THEN pktLength ← Lupine.StartNextPkt[pkt: pkt, pktLength: pktLength];
      Lupine.RpcPktDoubleWord[pkt, pktLength]↑ ← listLength;
      pktLength ← pktLength + 2;
      FOR thisNode1 ← properties, thisNode1.rest UNTIL thisNode1 =
          NIL DO
        BEGIN  -- Marshal thisNode1.first: AlpineEnvironment.UserPropertyValuePair
            -- to pkt.data[pktLength].
          pktLength ← Lupine.CopyToPkt[pkt: pkt, pktLength: pktLength,
              dataAdr: @thisNode1.first, dataLength: SIZE[AlpineEnvironment.UserPropertyValuePair],
              alwaysOnePkt: FALSE];
          BEGIN OPEN record: thisNode1.first;
          BEGIN  -- Marshal record.property: UserProperty to pkt.data[pktLength].
            IF pktLength+2 > RpcPrivate.maxDataLength
              THEN pktLength ← Lupine.StartNextPkt[pkt: pkt, pktLength:
                  pktLength];
            pkt.data[pktLength] ← record.property=NIL;  pktLength ←
                pktLength+1;
            IF record.property # NIL
              THEN BEGIN
                textRope: Rope.Text = Rope.InlineFlatten[r: record.property];
                pkt.data[pktLength] ← textRope.length;  pktLength ←
                    pktLength+1;
                pktLength ← Lupine.CopyToPkt[pkt: pkt, pktLength: pktLength,
                    dataAdr: BASE[DESCRIPTOR[textRope.text]], dataLength:
                    Lupine.WordsForChars[textRope.length], alwaysOnePkt:
                    FALSE];
                END;  -- IF record.property # NIL.
            END;  -- Marshal record.property.
          WITH variant: record SELECT FROM
            rope =>
              BEGIN  -- Marshal variant: RECORD [rope: Rope.ROPE] to
                  -- pkt.data[pktLength].
                BEGIN OPEN record: variant;
                BEGIN  -- Marshal record.rope: Rope.ROPE to pkt.data[pktLength].
                  IF pktLength+2 > RpcPrivate.maxDataLength
                    THEN pktLength ← Lupine.StartNextPkt[pkt: pkt,
                        pktLength: pktLength];
                  pkt.data[pktLength] ← record.rope=NIL;  pktLength
                      ← pktLength+1;
                  IF record.rope # NIL
                    THEN BEGIN
                      textRope: Rope.Text = Rope.InlineFlatten[r: record.rope];
                      pkt.data[pktLength] ← textRope.length;  pktLength
                          ← pktLength+1;
                      pktLength ← Lupine.CopyToPkt[pkt: pkt, pktLength:
                          pktLength, dataAdr: BASE[DESCRIPTOR[textRope.text]],
                          dataLength: Lupine.WordsForChars[textRope.length],
                          alwaysOnePkt: FALSE];
                      END;  -- IF record.rope # NIL.
                  END;  -- Marshal record.rope.
                END;  -- OPEN record: variant.
                END;  -- Marshal variant.
            ENDCASE => NULL;  -- WITH variant: record.
          END;  -- OPEN record: thisNode1.first.
          END;  -- Marshal thisNode1.first.
        ENDLOOP;  -- FOR thisNode1.
      END;  -- Marshal properties.
    RETURN[returnLength: pktLength];
    END;  -- ReadUserPropertiesStub.

  WriteUserPropertiesStub: --PROCEDURE [conversation: Conversation,
      -- openFileID: OpenFileID, properties: UserPropertyValuePairs, lock:
      -- LockOption]-- RpcPrivate.Dispatcher =
    BEGIN
    openFileID: OpenFileID;
    properties: UserPropertyValuePairs;
    lock: LockOption;
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID,
        lock (3): LockOption];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 4;
    BEGIN  -- OnePkt.
    onePkt: BOOLEAN = lastPkt;
    IF ~onePkt THEN BEGIN  -- Must move statics from pkt now.
      [openFileID: openFileID, lock: lock] ← argPkt↑;
      END;
    BEGIN  -- Unmarshal properties: UserPropertyValuePairs from pkt.data[pktLength].
      lastNode: UserPropertyValuePairs ← (properties ← NIL);
      listLength: Lupine.ListHeader;
      IF pktLength+2 > RpcPrivate.maxDataLength
        THEN pktLength ← Lupine.FinishThisPkt[pkt: pkt, pktLength:
            pktLength];
      listLength ← Lupine.RpcPktDoubleWord[pkt, pktLength]↑;
      pktLength ← pktLength + 2;
      WHILE listLength > 0 DO
        thisNode1: UserPropertyValuePairs = paramZones.gc.CONS[--DefaultValue--,NIL];
        BEGIN  -- Unmarshal thisNode1.first: AlpineEnvironment.UserPropertyValuePair
            -- from pkt.data[pktLength].
          pktLength ← Lupine.CopyFromPkt[pkt: pkt, pktLength: pktLength,
              dataAdr: @thisNode1.first, dataLength: SIZE[AlpineEnvironment.UserPropertyValuePair],
              alwaysOnePkt: FALSE];
          -- Restore garbled REFs to NIL following copy.
          BEGIN OPEN record: thisNode1.first;
          LOOPHOLE[record.property, LONG POINTER] ← NIL;
          WITH variant: record SELECT FROM
            rope =>
              BEGIN OPEN record: variant;
              LOOPHOLE[record.rope, LONG POINTER] ← NIL;
              END;  -- OPEN record: variant.
            ENDCASE => NULL;  -- WITH variant: record.
          END;  -- OPEN record: thisNode1.first.
          BEGIN OPEN record: thisNode1.first;
          BEGIN  -- Unmarshal record.property: UserProperty from pkt.data[pktLength].
            ropeIsNIL: Lupine.NilHeader;
            IF pktLength+2 > RpcPrivate.maxDataLength
              THEN pktLength ← Lupine.FinishThisPkt[pkt: pkt, pktLength:
                  pktLength];
            ropeIsNIL ← pkt.data[pktLength];  pktLength ← pktLength+1;
            IF ropeIsNIL
              THEN record.property ← NIL
              ELSE BEGIN
                ropeLength: Lupine.RopeHeader;
                textRope: Rope.Text;
                ropeLength ← pkt.data[pktLength];  pktLength ← pktLength+1;
                IF ropeLength > LAST[NAT]
                  THEN Lupine.UnmarshalingError;
                record.property ← textRope ← Rope.NewText[size: ropeLength];
                pktLength ← Lupine.CopyFromPkt[pkt: pkt, pktLength:
                    pktLength, dataAdr: BASE[DESCRIPTOR[textRope.text]],
                    dataLength: Lupine.WordsForChars[ropeLength], alwaysOnePkt:
                    FALSE];
                END;  -- IF ropeIsNIL.
            END;  -- Unmarshal record.property.
          WITH variant: record SELECT FROM
            rope =>
              BEGIN  -- Unmarshal variant: RECORD [rope: Rope.ROPE]
                  -- from pkt.data[pktLength].
                BEGIN OPEN record: variant;
                BEGIN  -- Unmarshal record.rope: Rope.ROPE from pkt.data[pktLength].
                  ropeIsNIL: Lupine.NilHeader;
                  IF pktLength+2 > RpcPrivate.maxDataLength
                    THEN pktLength ← Lupine.FinishThisPkt[pkt: pkt,
                        pktLength: pktLength];
                  ropeIsNIL ← pkt.data[pktLength];  pktLength ← pktLength+1;
                  IF ropeIsNIL
                    THEN record.rope ← NIL
                    ELSE BEGIN
                      ropeLength: Lupine.RopeHeader;
                      textRope: Rope.Text;
                      ropeLength ← pkt.data[pktLength];  pktLength
                          ← pktLength+1;
                      IF ropeLength > LAST[NAT]
                        THEN Lupine.UnmarshalingError;
                      record.rope ← textRope ← Rope.NewText[size: ropeLength];
                      pktLength ← Lupine.CopyFromPkt[pkt: pkt, pktLength:
                          pktLength, dataAdr: BASE[DESCRIPTOR[textRope.text]],
                          dataLength: Lupine.WordsForChars[ropeLength],
                          alwaysOnePkt: FALSE];
                      END;  -- IF ropeIsNIL.
                  END;  -- Unmarshal record.rope.
                END;  -- OPEN record: variant.
                END;  -- Unmarshal variant.
            ENDCASE => NULL;  -- WITH variant: record.
          END;  -- OPEN record: thisNode1.first.
          END;  -- Unmarshal thisNode1.first.
        IF lastNode # NIL
          THEN lastNode ← (lastNode.rest ← thisNode1)
          ELSE lastNode ← (properties ← thisNode1);
        listLength ← listLength - 1;
        ENDLOOP;  -- WHILE listLength > 0.
      END;  -- Unmarshal properties.
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    IF onePkt
      THEN WriteUserProperties[localConversation, argPkt.openFileID,
          properties, argPkt.lock]
      ELSE WriteUserProperties[localConversation, openFileID, properties,
          lock];
    END;  -- OnePkt.
    pktLength ← 0;
    RETURN[returnLength: pktLength];
    END;  -- WriteUserPropertiesStub.

  UnlockVersionStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID]-- RpcPrivate.Dispatcher =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 3;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    UnlockVersion[localConversation, argPkt.openFileID];
    pktLength ← 0;
    RETURN[returnLength: pktLength];
    END;  -- UnlockVersionStub.

  IncrementVersionStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID, increment: LONG INTEGER]-- RpcPrivate.Dispatcher =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID,
        increment (3): LONG INTEGER];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 5;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    IncrementVersion[localConversation, argPkt.openFileID, argPkt.increment];
    pktLength ← 0;
    RETURN[returnLength: pktLength];
    END;  -- IncrementVersionStub.

  GetSizeStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID, lock: LockOption]
    -- RETURNS [size: PageCount]-- RpcPrivate.Dispatcher =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID,
        lock (3): LockOption];
    ResultOverlay: TYPE = MACHINE DEPENDENT RECORD [
        size (0): PageCount];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    resPkt: LONG POINTER TO ResultOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 4;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    [resPkt.size] ← GetSize[localConversation, argPkt.openFileID, argPkt.lock];
    pktLength ← 2;
    RETURN[returnLength: pktLength];
    END;  -- GetSizeStub.

  SetSizeStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID, size: PageCount, lock: LockOption]-- RpcPrivate.Dispatcher
      =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID,
        size (3): PageCount, lock (5): LockOption];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 6;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    SetSize[localConversation, argPkt.openFileID, argPkt.size, argPkt.lock];
    pktLength ← 0;
    RETURN[returnLength: pktLength];
    END;  -- SetSizeStub.

  UnlockFileStub: --PROCEDURE [conversation: Conversation, openFileID:
      -- OpenFileID, retainCacheLocks: BOOLEAN]-- RpcPrivate.Dispatcher
      =
    BEGIN
    ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
        transferIndex (0): RpcControl.ProcedureIndex, openFileID (1): OpenFileID,
        retainCacheLocks (3): BOOLEAN];
    argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
    pktLength: RpcPrivate.DataLength ← 4;
    Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
    UnlockFile[localConversation, argPkt.openFileID, argPkt.retainCacheLocks];
    pktLength ← 0;
    RETURN[returnLength: pktLength];
    END;  -- UnlockFileStub.


-- Marshall/Unmarshal procedures.
UnmarshalCachePageLockConversions: PROC[pkt: RpcPrivate.RPCPkt, pktLength0:
    RpcPrivate.DataLength]
  RETURNS[value: AlpineFile.CachePageLockConversions, pktLength: RpcPrivate.DataLength]
      = BEGIN
  pktLength ← pktLength0; {
  BEGIN  -- Unmarshal value↑: AlpineEnvironment.CachePageLockConversionsObject
      -- from pkt.data[pktLength].
    recordIsNIL: Lupine.NilHeader;
    IF pktLength+3 > RpcPrivate.maxDataLength
      THEN pktLength ← Lupine.FinishThisPkt[pkt: pkt, pktLength: pktLength];
    recordIsNIL ← pkt.data[pktLength];  pktLength ← pktLength+1;
    IF recordIsNIL
      THEN value ← NIL
      ELSE BEGIN
        seqLength: Lupine.SequenceHeader;
        seqLength ← Lupine.RpcPktDoubleWord[pkt, pktLength]↑;
        pktLength ← pktLength + 2;
        value ← (paramZones.gc.NEW[AlpineEnvironment.CachePageLockConversionsObject[Lupine.SHORT[seqLength]]]);
        pktLength ← Lupine.CopyFromPkt[pkt: pkt, pktLength: pktLength,
            dataAdr: LOOPHOLE[value], dataLength: SIZE[AlpineEnvironment.CachePageLockConversionsObject[LENGTH[DESCRIPTOR[value↑]]]],
            alwaysOnePkt: FALSE];
        END;  -- IF recordIsNIL.
    END;  -- Unmarshal value↑.
  };END;



-- No module initialization.

END.  -- AlpineFileRpcServerImpl.