-- Copyright (C) 1984  by Xerox Corporation. All rights reserved. 
--FloppyImplPublicC.mesa   (last edited by JXG     on 18-Jan-84 17:25:19)

DIRECTORY
  Environment USING [wordsPerPage],
  File USING [File, PageCount, PageNumber, Type],
  Floppy USING [
    AlreadyFormatted, BootFilePointer, Close, CopyFromPilotFile, CopyToPilotFile,
    DataError, Density, Error, ErrorType, FileHandle, FileID, Format, 
    GetAttributes,    GetBootFiles, GetFileAttributes, GetNextFile, nullFileID,
    Open, PageCount,    PageNumber, SetBootFiles, SetRootFile, Sides,
    VolumeHandle],
  FloppyChannel USING [DiskAddress],
  FloppyFormat USING [
    ConvertPageNumber, DiskAddressToSector, firstDataAddress, nullSector, Sector,
    SectorToDiskAddress],
  FloppyImplInterface,
  Inline USING [LowHalf],
  Space USING [Interval, Map, Unmap],
  SpecialFloppy USING [CreateInitialMicrocodeWithID, CreateFileAtAddressWithID,
    Error, ErrorType, GetFileAtDiskAddress, nullDiskAddress];
  

FloppyImplPublicC: MONITOR LOCKS volumeDesc USING volumeDesc:
  FloppyImplInterface.VolumeDesc
  IMPORTS
    Floppy, FloppyFormat, FloppyImplInterface, Inline, Space,
    SpecialFloppy
  EXPORTS Floppy, SpecialFloppy =

  BEGIN OPEN FloppyImplInterface;

  FloppyFileInfo: TYPE = MACHINE DEPENDENT RECORD [
    fileID(0): Floppy.FileID,
    size(2): Floppy.PageCount,
    fileType(4): File.Type,
    offset(5): File.PageNumber];

  FloppyInfoSeq: TYPE = RECORD [
    length: CARDINAL, item: ARRAY [0..0) OF FloppyFileInfo];

  FloppyInfoSeqType: TYPE = LONG POINTER TO FloppyInfoSeq;

  HeaderPage0: TYPE = MACHINE DEPENDENT RECORD [
    seal(0): CARDINAL ← ImageSeal,
    version(1): CARDINAL← ImageVersion,
    currentNumberOfFiles(2): CARDINAL,
    maxNumberOfFiles(3): CARDINAL,
    fileList(4): Floppy.FileHandle,
    rootFile(8): Floppy.FileHandle,
    density(12): Floppy.Density,
    sides(13): Floppy.Sides,
    initialUCode(14): Floppy.BootFilePointer,
    pilotUCode(18): Floppy.BootFilePointer,
    diagUCode(22): Floppy.BootFilePointer,
    germ(26): Floppy.BootFilePointer, 
    pilotBootFile(30): Floppy.BootFilePointer,
    pilotUCodeAddress(34): FloppyChannel.DiskAddress,
    diagUCodeAddress(36): FloppyChannel.DiskAddress,
    germAddress(38): FloppyChannel.DiskAddress,
    pilotBootFileAddress(40): FloppyChannel.DiskAddress,
    sizeOfFile(42): Floppy.PageCount,
    pseudoRootPageIndex(44): CARDINAL,
    labelStringBody(45): StringBody];
    
  ImageSeal: CARDINAL = 146363B;
  ImageVersion: CARDINAL = 1;
  PseudoPVRootPageAddress: FloppyChannel.DiskAddress = [
      cylinder: 4, head: 0, sector: 1];


  CreateFileAtAddress: PUBLIC PROCEDURE [
    volume: Floppy.VolumeHandle, size: Floppy.PageCount, type: File.Type,
    location: FloppyChannel.DiskAddress] RETURNS [file: Floppy.FileHandle] =
    BEGIN
    volumeDesc: VolumeDesc;
    file.volume ← volume;
    volumeDesc ← ValidateHandle[volume];
    file.file ← CreateFileAtAddressWithIDInternal[
      volumeDesc, Floppy.nullFileID, size, type, location];
    END;

  CreateFileAtAddressWithID: PUBLIC PROCEDURE [
    volume: Floppy.VolumeHandle, id: Floppy.FileID, size: Floppy.PageCount,
    type: File.Type, location: FloppyChannel.DiskAddress]
    RETURNS [file: Floppy.FileHandle] =
    BEGIN
    volumeDesc: VolumeDesc;
    file.volume ← volume;
    volumeDesc ← ValidateHandle[volume];
    file.file ← CreateFileAtAddressWithIDInternal[
      volumeDesc, id, size, type, location];
    END;

  CreateFileAtAddressWithIDInternal: ENTRY PROCEDURE [
    volumeDesc: VolumeDesc, id: Floppy.FileID, size: Floppy.PageCount,
    type: File.Type, location: FloppyChannel.DiskAddress]
    RETURNS [file: Floppy.FileID] =
    BEGIN
    ENABLE BEGIN UNWIND => NULL; END;
    startSector: FloppyFormat.Sector;
    IF ~volumeDesc.open THEN RETURN WITH ERROR Floppy.Error[volumeNotOpen];
    IF location = SpecialFloppy.nullDiskAddress THEN
      startSector ← FloppyFormat.nullSector
    ELSE
      BEGIN
      startSector ← FloppyFormat.DiskAddressToSector[
        location, volumeDesc.sectorNine.cylinders,
        volumeDesc.sectorNine.tracksPerCylinder,
        volumeDesc.sectorNine.sectorsPerTrack];
      --check that location is valid
      IF
        (FloppyFormat.DiskAddressToSector[
          FloppyFormat.firstDataAddress, volumeDesc.sectorNine.cylinders,
          volumeDesc.sectorNine.tracksPerCylinder,
          volumeDesc.sectorNine.sectorsPerTrack] > startSector)
        OR (startSector + size > volumeDesc.numPages - 1) THEN
        RETURN WITH ERROR SpecialFloppy.Error[invalidDiskAddress];
      END;
    file ← CreateFileInternal[volumeDesc, size, type, startSector, id].fileID;
    END;


  CreateFloppyFromImage: PUBLIC PROCEDURE [
    floppyDrive: CARDINAL, imageFile: File.File,
    firstImagePage: File.PageNumber, reformatFloppy: BOOLEAN,
    floppyDensity: Floppy.Density, floppySides: Floppy.Sides,
    numberOfFiles: CARDINAL, newLabelString: LONG STRING] =
    
    BEGIN
    floppyFileInfoPerPage: CARDINAL = Environment.wordsPerPage/SIZE[FloppyFileInfo];
    headerPage0Ptr: LONG POINTER TO HeaderPage0;
    floppyHandle: Floppy.VolumeHandle;
    space1Interval: Space.Interval;
    space2Interval: Space.Interval;
    floppyInfoSeqPtr: FloppyInfoSeqType;
    fileHandle: Floppy.FileHandle;
    oldLabelString: LONG STRING;
    index: CARDINAL ← 0;
    spaceAvailable: Floppy.PageCount;
    dataErrorFile: Floppy.FileHandle;
    dataErrorPage: Floppy.PageNumber;

    BEGIN OPEN hdr:headerPage0Ptr, flptr: floppyInfoSeqPtr;
    space1Interval ← Space.Map[
      [file: imageFile, base: firstImagePage, count: 1]];
    headerPage0Ptr ← space1Interval.pointer;
    IF hdr.seal # ImageSeal OR hdr.version # ImageVersion THEN
      ERROR Floppy.Error[error: floppyImageInvalid];
    IF numberOfFiles # 0 AND hdr.currentNumberOfFiles > numberOfFiles THEN
      ERROR Floppy.Error[error: fileListLengthTooShort];
    oldLabelString ← @hdr.labelStringBody;
    space2Interval ← Space.Map[
      [file: imageFile, base: firstImagePage + 1, count: hdr.currentNumberOfFiles/floppyFileInfoPerPage + 1]];
    floppyInfoSeqPtr ← space2Interval.pointer;
    Floppy.Format[
      drive: floppyDrive,
      maxNumberOfFileListEntries:
      IF numberOfFiles = 0 THEN hdr.maxNumberOfFiles ELSE numberOfFiles,
      labelString:
      IF newLabelString = NIL THEN oldLabelString
      ELSE IF newLabelString.length = 0 THEN oldLabelString ELSE newLabelString,
      density: floppyDensity, sides: floppySides !
      Floppy.AlreadyFormatted => IF reformatFloppy THEN RESUME ELSE REJECT];
    floppyHandle ← Floppy.Open[floppyDrive];
    [freeSpace: spaceAvailable] ← Floppy.GetAttributes [
      volume: floppyHandle, labelString: NIL];
    IF hdr.sizeOfFile > spaceAvailable THEN ERROR Floppy.Error[error: floppySpaceTooSmall];
    

    FOR index IN [0..flptr.length) DO
    
      SELECT flptr.item[index].fileID FROM
        Floppy.nullFileID => EXIT;
        hdr.initialUCode.file =>
          fileHandle ← SpecialFloppy.CreateInitialMicrocodeWithID[
            volume: floppyHandle, id: flptr.item[index].fileID, size:
	    flptr.item[index].size, type: flptr.item[index].fileType,
	    startingPageNumber: hdr.initialUCode.page !
            SpecialFloppy.Error => SELECT error FROM
	      IDAlreadyInUse => ERROR Floppy.Error[error: floppyImageInvalid];
	      ENDCASE];
        flptr.item[hdr.pseudoRootPageIndex].fileID =>
          fileHandle ← SpecialFloppy.CreateFileAtAddressWithID[
            volume: floppyHandle, id: flptr.item[index].fileID,
	    size: flptr.item[index].size, type: flptr.item[index].fileType,
	    location: PseudoPVRootPageAddress !
            SpecialFloppy.Error => SELECT error FROM
	      IDAlreadyInUse => ERROR Floppy.Error[error: floppyImageInvalid];
	      ENDCASE];
        hdr.pilotUCode.file =>
	  fileHandle ← SpecialFloppy.CreateFileAtAddressWithID[
            volume: floppyHandle, id: flptr.item[index].fileID,
	    size: flptr.item[index].size, type: flptr.item[index].fileType,
	    location: hdr.pilotUCodeAddress !
            SpecialFloppy.Error => SELECT error FROM
	      IDAlreadyInUse => ERROR Floppy.Error[error: floppyImageInvalid];
	      ENDCASE];
        hdr.diagUCode.file =>
	  fileHandle ← SpecialFloppy.CreateFileAtAddressWithID[
            volume: floppyHandle, id: flptr.item[index].fileID,
	    size: flptr.item[index].size, type: flptr.item[index].fileType,
	    location: hdr.diagUCodeAddress !
            SpecialFloppy.Error => SELECT error FROM
	      IDAlreadyInUse => ERROR Floppy.Error[error: floppyImageInvalid];
	      ENDCASE];
	hdr.germ.file =>
	  fileHandle ← SpecialFloppy.CreateFileAtAddressWithID[
            volume: floppyHandle, id: flptr.item[index].fileID,
	    size: flptr.item[index].size, type: flptr.item[index].fileType,
	    location: hdr.germAddress !
            SpecialFloppy.Error => SELECT error FROM
	      IDAlreadyInUse => ERROR Floppy.Error[error: floppyImageInvalid];
	      ENDCASE];
        hdr.pilotBootFile.file =>
	  fileHandle ← SpecialFloppy.CreateFileAtAddressWithID[
            volume: floppyHandle, id: flptr.item[index].fileID,
	    size: flptr.item[index].size, type: flptr.item[index].fileType,
	    location: hdr.pilotBootFileAddress !
            SpecialFloppy.Error => SELECT error FROM
	      IDAlreadyInUse => ERROR Floppy.Error[error: floppyImageInvalid];
	      ENDCASE];
        ENDCASE =>
          fileHandle ← SpecialFloppy.CreateFileAtAddressWithID[
            volume: floppyHandle, id: flptr.item[index].fileID, 
	    size: flptr.item[index].size, type: flptr.item[index].fileType,
	    location: SpecialFloppy.nullDiskAddress !
            SpecialFloppy.Error => SELECT error FROM
	      IDAlreadyInUse => ERROR Floppy.Error[error: floppyImageInvalid];
	      ENDCASE];
      fileHandle ← [floppyHandle, flptr.item[index].fileID];
     Floppy. CopyFromPilotFile[
        pilotFile: imageFile, floppyFile: fileHandle,
        firstPilotPage: firstImagePage + flptr.item[index].offset, firstFloppyPage: 0,
        count: flptr.item[index].size !
        Floppy.DataError =>
          BEGIN
	    dataErrorFile ← file;
	    dataErrorPage ← page;
	    space2Interval.pointer ← Space.Unmap[space2Interval.pointer];
            space1Interval.pointer ← Space.Unmap[space1Interval.pointer];
            Floppy.Close[floppyHandle];
	    GOTO errorExit;
          END; ];
      ENDLOOP;

    Floppy.SetBootFiles[
      volume: floppyHandle, pilotMicrocode: hdr.pilotUCode,
      diagnosticMicrocode: hdr.diagUCode, germ: hdr.germ, 
      pilotBootFile: hdr.pilotBootFile];
    IF hdr.rootFile.file # Floppy.nullFileID THEN Floppy.SetRootFile[hdr.rootFile];
    space2Interval.pointer ← Space.Unmap[space2Interval.pointer];
    space1Interval.pointer ← Space.Unmap[space1Interval.pointer];
    Floppy.Close[floppyHandle];
    EXITS
      errorExit => ERROR Floppy.DataError[file: dataErrorFile, page: dataErrorPage , vm: NIL];
    END;
    END;


  CreateInitialMicrocodeWithID: PUBLIC PROCEDURE [
    volume: Floppy.VolumeHandle, id: Floppy.FileID, size: Floppy.PageCount,
    type: File.Type, startingPageNumber: Floppy.PageNumber]
    RETURNS [file: Floppy.FileHandle] =
    BEGIN
    volumeDesc: VolumeDesc;
    file.volume ← volume;
    volumeDesc ← ValidateHandle[volume];
    file.file ← CreateInitialMicrocodeInternal[
      volumeDesc, size, type, startingPageNumber, id];
    END;


  GetDiskAddress: PUBLIC PROCEDURE [
    file: Floppy.FileHandle, page: Floppy.PageNumber]
    RETURNS [diskAddress: FloppyChannel.DiskAddress] =
    BEGIN
    volumeDesc: VolumeDesc;
    GetDiskAddressInternal: ENTRY PROCEDURE [
      volumeDesc: VolumeDesc, page: Floppy.PageNumber] =
      BEGIN
      ENABLE BEGIN UNWIND => NULL; END;
      sector: FloppyFormat.Sector;
      IF ~volumeDesc.open THEN RETURN WITH ERROR Floppy.Error[volumeNotOpen];
      sector ←
        FindFile[volumeDesc, file.file].address + FloppyFormat.ConvertPageNumber[
          page];
      diskAddress ← FloppyFormat.SectorToDiskAddress[
        sector, volumeDesc.sectorNine.cylinders,
        volumeDesc.sectorNine.tracksPerCylinder,
        volumeDesc.sectorNine.sectorsPerTrack];
      END;
    volumeDesc ← ValidateHandle[file.volume];
    GetDiskAddressInternal[volumeDesc, page];
    END;

  GetFileAtDiskAddress: PUBLIC PROCEDURE [
    volume: Floppy.VolumeHandle, diskAddress: FloppyChannel.DiskAddress]
    RETURNS [file: Floppy.FileHandle, pageNumber: Floppy.PageNumber] =
    BEGIN
    volumeDesc: VolumeDesc;
    GetFileAtDiskAddressInternal: ENTRY PROCEDURE [
      volumeDesc: VolumeDesc, diskAddress: FloppyChannel.DiskAddress] =
      BEGIN
      ENABLE BEGIN UNWIND => NULL; END;
      sector: FloppyFormat.Sector;
      file.volume ← volume;
      IF ~volumeDesc.open THEN RETURN WITH ERROR Floppy.Error[volumeNotOpen];
      sector ← FloppyFormat.DiskAddressToSector[
        diskAddress, volumeDesc.sectorNine.cylinders,
        volumeDesc.sectorNine.tracksPerCylinder,
        volumeDesc.sectorNine.sectorsPerTrack];
      IF volumeDesc.allocationMap[sector] ~= allocated THEN
        BEGIN file.file ← Floppy.nullFileID; pageNumber ← 0; RETURN; END
      ELSE
        BEGIN
        file.file ← Floppy.nullFileID;
        pageNumber ← 0;
        FOR i: CARDINAL IN [0..volumeDesc.fileList.count) DO
          IF sector IN
            [volumeDesc.fileList.files[
               i].location..volumeDesc.fileList.files[i].location +
                              volumeDesc.fileList.files[i].size) THEN
            BEGIN
            file.file ← volumeDesc.fileList.files[i].file;
            pageNumber ← sector - volumeDesc.fileList.files[i].location;
            EXIT;
            END;
          ENDLOOP;
        END;
      END;
    volumeDesc ← ValidateHandle[volume];
    GetFileAtDiskAddressInternal[volumeDesc, diskAddress];
    END;


  GetCurrentNumberOfFiles: PROCEDURE [volume: Floppy.VolumeHandle]
    RETURNS [currentNumberOfFiles: CARDINAL] =
    BEGIN
    volumeDesc: VolumeDesc;
    GetCurrentNumberOfFilesInternal: ENTRY PROCEDURE [volumeDesc: VolumeDesc] =
      BEGIN
      ENABLE BEGIN UNWIND => NULL; END;
      IF ~volumeDesc.open THEN RETURN WITH ERROR Floppy.Error[volumeNotOpen];
      currentNumberOfFiles ← volumeDesc.fileList.count;
      END;
    volumeDesc ← ValidateHandle[volume];
    GetCurrentNumberOfFilesInternal[volumeDesc];
    END;


  GetImageAttributes: PUBLIC PROCEDURE [
    imageFile: File.File, firstImagePage: File.PageNumber, name: LONG STRING]
    RETURNS [
      maxNumberOfFiles: CARDINAL, currentNumberOfFiles: CARDINAL,
      density: Floppy.Density[single..double], sides: Floppy.Sides[one..two]] =
    BEGIN
    headerPage0Ptr: LONG POINTER TO HeaderPage0;
    spaceInterval: Space.Interval;
    labelString: LONG STRING;

    spaceInterval ← Space.Map[[file: imageFile, base: firstImagePage, count: 1]];
    headerPage0Ptr ← spaceInterval.pointer;
    labelString ← @headerPage0Ptr.labelStringBody;
    IF name # NIL THEN
      BEGIN
      FOR index: CARDINAL IN [0..MIN[name.maxlength, labelString.length]) DO
        name.text[index] ← labelString.text[index]; ENDLOOP;
      name.length ← labelString.length;
      END;
    maxNumberOfFiles ← headerPage0Ptr.maxNumberOfFiles;
    currentNumberOfFiles ← headerPage0Ptr.currentNumberOfFiles;
    density ← headerPage0Ptr.density;
    sides ← headerPage0Ptr.sides;
    spaceInterval.pointer ← Space.Unmap[spaceInterval.pointer];
    END;



  MakeImage: PUBLIC PROCEDURE [
    floppyDrive: CARDINAL, imageFile: File.File,
    firstImagePage: File.PageNumber] =
    BEGIN
    
    floppyFileInfoPerPage: CARDINAL = Environment.wordsPerPage/SIZE[FloppyFileInfo];
    headerPage0Ptr: LONG POINTER TO HeaderPage0;
    floppyHandle: Floppy.VolumeHandle;
    space1Interval: Space.Interval;
    space2Interval: Space.Interval;
    floppyInfoSeqPtr: FloppyInfoSeqType;
    labelString: LONG STRING;
    numOfFiles: CARDINAL;
    fileHandle: Floppy.FileHandle;
    floppyID: Floppy.FileID ← Floppy.nullFileID;
    index: CARDINAL ← 0;
    numOfPages: LONG CARDINAL;
    pages: Floppy.PageCount;
    pseudoRootPageHandle: Floppy.FileHandle;
    dataErrorFile: Floppy.FileHandle;
    dataErrorPage: Floppy.PageNumber;

    BEGIN OPEN hdr: headerPage0Ptr, flptr: floppyInfoSeqPtr;
    floppyHandle ← Floppy.Open[floppyDrive];
    [pages: pages, files: numOfFiles] ← PagesForFloppyInfoSeq[
      floppyHandle];
    numOfPages ← pages;
    space2Interval ← Space.Map[[file: imageFile, base: firstImagePage + 1, count: pages]];
    floppyInfoSeqPtr ← space2Interval.pointer;
    space1Interval ← Space.Map[[file: imageFile, base: firstImagePage, count: 1]];
    headerPage0Ptr ← space1Interval.pointer;
    flptr.length ← numOfFiles - 1;  -- The fileList is not included
    numOfPages ← numOfPages + 1;
    [file: pseudoRootPageHandle] ← SpecialFloppy .GetFileAtDiskAddress[
      volume: floppyHandle, diskAddress: PseudoPVRootPageAddress];
    fileHandle ← [floppyHandle, floppyID];
    fileHandle ← Floppy.GetNextFile[fileHandle];

    FOR index IN [0..flptr.length) DO
    
      SELECT fileHandle.file FROM 
        pseudoRootPageHandle.file => hdr.pseudoRootPageIndex ← index;
	hdr.pilotUCode.file =>
	  hdr.pilotUCodeAddress ← GetDiskAddress[file: fileHandle, page: 0];
        hdr.diagUCode.file =>
	  hdr.diagUCodeAddress ← GetDiskAddress[file: fileHandle, page: 0];
	hdr.germ.file =>
	  hdr.germAddress ← GetDiskAddress[file: fileHandle, page: 0];
	hdr.pilotBootFile.file =>
	  hdr.pilotBootFileAddress ← GetDiskAddress[file: fileHandle, page: 0];
	ENDCASE => NULL;
	
      [size: flptr.item[index].size, type: flptr.item[index].fileType] ←
        Floppy.GetFileAttributes[fileHandle];
      flptr.item[index].fileID ← fileHandle.file;
      flptr.item[index].offset ← numOfPages;
      Floppy.CopyToPilotFile[
        floppyFile: fileHandle, pilotFile: imageFile, firstFloppyPage: 0,
        firstPilotPage: firstImagePage + flptr.item[index].offset,
        count: flptr.item[index].size !
        Floppy.DataError =>
          BEGIN
	    dataErrorFile ← file;
	    dataErrorPage ← page;
            space1Interval.pointer ← Space.Unmap[space1Interval.pointer];
	    space2Interval.pointer ← Space.Unmap[space2Interval.pointer];
            Floppy.Close[floppyHandle];
	    GOTO errorExit;
          END; ];
      numOfPages ← numOfPages + flptr.item[index].size;
      fileHandle ← Floppy.GetNextFile[fileHandle];
      ENDLOOP;

    numOfPages ← numOfPages - flptr.item[0].offset;
    space2Interval.pointer ← Space.Unmap[space2Interval.pointer];
    
    labelString ← @hdr.labelStringBody;
    labelString↑ ← StringBody[length: 0, maxlength: 128, text:];
    hdr.seal ← ImageSeal;
    hdr.version ← ImageVersion;
    hdr.currentNumberOfFiles ← GetCurrentNumberOfFiles[floppyHandle];
    [fileList: hdr.fileList, rootFile: hdr.rootFile, density: hdr.density,
    sides: hdr.sides, maxFileListEntries: hdr.maxNumberOfFiles] ←
      Floppy.GetAttributes[volume: floppyHandle, labelString: labelString];
    [hdr.initialUCode, hdr.pilotUCode, hdr.diagUCode, hdr.germ, hdr.pilotBootFile] ←
      Floppy.GetBootFiles[floppyHandle];
    hdr.sizeOfFile ← numOfPages;
    space1Interval.pointer ← Space.Unmap[space1Interval.pointer];
    Floppy.Close[floppyHandle];
    EXITS
      errorExit => ERROR Floppy.DataError[file: dataErrorFile, page: dataErrorPage, vm: NIL];
    END;
    END;



  PagesForFloppyInfoSeq: PROCEDURE [
    floppyHandle: Floppy.VolumeHandle]
    RETURNS [pages: File.PageCount, files: CARDINAL] =
    BEGIN

    files ← GetCurrentNumberOfFiles[floppyHandle];
    pages ← (files*SIZE[FloppyFileInfo] + Environment.wordsPerPage -1)/ Environment.wordsPerPage;
    END;


  PagesForImage: PUBLIC PROCEDURE [floppyDrive: CARDINAL]
    RETURNS [File.PageCount] =

    BEGIN
    floppyHandle: Floppy.VolumeHandle;
    fileHandle: Floppy.FileHandle;
    floppyID: Floppy.FileID ← Floppy.nullFileID;
    numOfPages: File.PageCount ← 1;  -- for the header
    sizeOfFile: Floppy.PageCount;
    pages: File.PageCount;

    floppyHandle ← Floppy.Open[floppyDrive];
    [pages: pages] ← PagesForFloppyInfoSeq[floppyHandle];
    numOfPages ← numOfPages + pages;
    fileHandle ← [floppyHandle, floppyID];
    fileHandle ← Floppy.GetNextFile[fileHandle];
    WHILE fileHandle.file # Floppy.nullFileID DO
      [size: sizeOfFile] ← Floppy.GetFileAttributes[fileHandle];
      numOfPages ← numOfPages + LOOPHOLE[sizeOfFile, LONG CARDINAL];
      fileHandle ← Floppy.GetNextFile[fileHandle];
      ENDLOOP;
    Floppy.Close[floppyHandle];
    RETURN[numOfPages];
    END;




  END.


LOG
Time:   1-Feb-82 15:08:14  by: LXD      
	Created File
Time:   9-Feb-82 19:04:53  by: LXD      
	added GetDiskAddress
Time:  11-Feb-82 18:05:30  by: LXD      
	added GetFileAtDiskAddress
Time:   6-Aug-82 18:47:49  by: AWL      
	Implemented GetFileListAttributes, CreateWithIDAtLocation,
CreateInitialMicrocodeWIthID
Time:   2-Nov-82 11:15:25  By: EKN   
   	Added CreateFloppyFromImage, GetImageAttributes, MakeImage,
	PagesForImage, PagesForFloppyInfoSeq, FCError. 
	(written by DXG     )
Time:	 2-Mar-83 15:16:57 By: EKN   
	Updated Space Stuff to Klamath.  ChangedGetFileListAttributes to GetCurrentNumberOfFiles. References to SpecialFloppyExtras and FloppyExtras are now SpecialFloppy and Floppy, respectively.
Time:	18-Jan-84 15:14:36 By: JXG     off by one error
Time:	18-Jan-84 17:26:08 By: JXG     undid erroneous fix