home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / utils / dskutl / swp-ms10.ark / TRAMDF.IF0 < prev    next >
Text File  |  1989-09-27  |  18KB  |  414 lines

  1.  
  2. {* -------------------------------------------------------------------------
  3.  *                   G L O B A L   D E F I N I T I O N S
  4.  * ------------------------------------------------------------------------- *}
  5.  
  6. const
  7.    Version    =   '1.9110' ;  { Version number of TraMDF }
  8.    DefaultDate= '19911101' ;  { Compilation date of TraMDF }
  9. {*
  10.  * Sizes of buffers and tables.
  11.  *}
  12.    SectorSize    =  511 ;  { Size of a sector - 1 }
  13.    ClusterSize   = 1023 ;  { Size of a cluster - 1 }
  14.    FatSize       = 1535 ;  { Size of a FAT - 1 }
  15.    BytesPerFcb   =   32 ;  { Size of an MS-DOS FCB }
  16.    BytesPerRecord=  128 ;  { Size of a CP/M record }
  17.    ErrorStackSize=    3 ;  { Size of stack of errormessages - 1 }
  18.    MsdosPathSize =    7 ;  { Maximum subdirectory nesting level }
  19. {*
  20.  * BDOS function codes.
  21.  *}
  22.    SetCurrentDrive  = 14 ;  { Login disk }
  23.    GetCurrentDrive  = 25 ;  { Retrieve current default drive }
  24.    GetAllocationMap = 27 ;  { Retrieve address of allocation bitmap }
  25.    SetFileAttributes= 30 ;  { (Re)set file attributes }
  26. {*
  27.  * BIOS function codes.  These codes are off by one because TP assigns
  28.  * function code zero to the WarmBoot entry.
  29.  *}
  30.    SelectDrive =  8 ;  { Select a drive }
  31.    SelectTrack =  9 ;  { Select LOGICAL track }
  32.    SelectRecord= 10 ;  { Select ordinal of record to transfer }
  33.    SelectBuffer= 11 ;  { Select record buffer address }
  34.    ReadRecord  = 12 ;  { Read one record }
  35.    WriteRecord = 13 ;  { Write one record }
  36.  
  37. type
  38.    OSs      = ( Cpm, Msdos )        ;  { Supported Operating (file) systems }
  39.    FileNames= array[01..11] of Char ;  { CP/M and MS-DOS file name }
  40.    FileSizes= array[00..03] of Byte ;  { MS-DOS file size }
  41.    FileAttributes= ( ReadOnly    , Hidden , System , Volume ,
  42.                      SubDirectory, Archive, Unused6, Unused7 ) ;
  43.    FileClasses   = ( TextFile, BinaryFile, AskUser ) ;
  44.  
  45.    EntryTypes= ( VolumeNameEntry, SubdirectoryNameEntry, FileNameEntry,
  46.                  FreeEntry      , UnusedEntry          , EndOfDirectory  ) ;
  47.  
  48.    SearchPositions= ( BeforeFirstEntry, InSubDirectory, AfterLastEntry ) ;
  49.  
  50.    DateStrings  = string[ 8] ;  { Numeric date string }
  51.    ErrorMessages= string[48] ;  { Error message string }
  52.  
  53. {*
  54.  * Define the structure of the (XLT and) DPB within BIOS.  The XLT is
  55.  * used to map sector numbers (see procedure ReadSector).  The DPB, and
  56.  * especially its extension, is used to hold the characteristics of the
  57.  * disk.  It is assumed that modification of the DPB together with some
  58.  * address mapping is sufficient to read and write MS-DOS disks.
  59.  *
  60.  * CAUTION : The definition of the DPB is system dependent, except for the
  61.  *           fields SPT through OFF which are standard for CP/M.
  62.  *}
  63.    DPBs = record
  64.            XLT: array[0..25] of Byte ;  { sector translate table }
  65.            SPT: Integer ;  { Number of logical sectors per track }
  66.            BSH:    Byte ;  { Data allocation block shift factor }
  67.            BLM:    Byte ;  { Data allocation block mask }
  68.            EXM:    Byte ;  { Extent mask }
  69.            DSM: Integer ;  { Maximum data block number }
  70.            DRM: Integer ;  { Maximum directory entry number }
  71.            ALM: Integer ;  { Directory allocation mask }
  72.            CKS: Integer ;  { Directory check vector size }
  73.            OFF: Integer ;  { Number of reserved tracks }
  74.            FNO:    Byte ;  { Flags & Numbering scheme Ordinal }
  75.            DDS:    Byte ;  { Density & Drive Select }
  76.            PDA:    Byte ;  { Physical Drive Address }
  77.            TFC:    Byte ;  { Track # on First Cylinder }
  78.            PSS:    Byte ;  { Physical Sector Size }
  79.            PCD:    Byte ;  { Number of cylinders per disk }
  80.            PST:    Byte ;  { Number of sectors per track }
  81.           end ;
  82. {*
  83.  * Define the File_Control_Block (FCB) of both CP/M and MS-DOS, that is
  84.  * the structure of the directory entries.  Thus, the CP/M FCB can only
  85.  * be used for directory search operations, while for actual CP/M file
  86.  * actions an untyped pascal file is used.
  87.  *}
  88.    CpmFCBs= record
  89.              Drive   :      Byte ;  { Drive code }
  90.              FileName: FileNames ;  { Name including type }
  91.              Extent  :      Byte ;  { Extent number }
  92.              S1, S2  :      Byte ;  { Reserved for CP/M internal use }
  93.              RecCnt  :      Byte ;  { Records in current extent }
  94.              Blocks  : array[16..31] of Byte ;  { Allocated blocks }
  95.           {  RecPntr :      Byte ;  { Current record ordinal }
  96.           {  R0,R1,R2:      Byte ;  { Random record number }
  97.             end ;
  98.  
  99.   MsdosFCBs= record
  100.               FileName :             FileNames ;  { Name including type }
  101.               Attribute: set of FileAttributes ;  { File attributes }
  102.               Rsrvd    : array[12..21] of Byte ;
  103.               Time     :               Integer ;  { Time of last mod }
  104.               Date     :               Integer ;  { Date of last mod }
  105.               Cluster  :               Integer ;  { First cluster in file }
  106.               Size     :             FileSizes ;  { Size of file }
  107.              end ;
  108. {*
  109.  * Define the structure of the Turbo Pascal File Information Block (FIB).
  110.  * It is used in BDOS file calls: the above defined CpmFcbs cannot be used
  111.  * for this purpose!
  112.  *}
  113.    CpmFibs= record
  114.               Filler: array[0..11] of Byte ;  { TP information }
  115.               Fcb   : array[0..35] of Byte ;  { BDOS information }
  116.             end ;  { of record }
  117. {*
  118.  * Define a record to hold the disk drive configuration information.  This
  119.  * information is partly derived from the current system configuration and
  120.  * it is partly hardcoded in procedure DetermineDriveAttributes.
  121.  *
  122.  * The device address is included because the Aster BIOS allows one to
  123.  * assign more than one logical drive to one physical drive, while at
  124.  * the same time it does not care about the associated problems.  Using
  125.  * DevAddress, TraMDF avoids using one physical drive for CP/M and MS-DOS
  126.  * simultaneously.
  127.  *}
  128.    DriveNames     = 'A'..'P' ;  { Legal drive names }
  129.    DriveAttributes= record
  130.                      DpbAddress:   ^DPBs ;  { Address of it's (XLT &) DPB }
  131.                      DevAddress: Integer ;  { Physical device address }
  132.                      Cylinders : Integer ;  { Number of cylinders }
  133.                      Heads     : Integer ;  { Number of heads }
  134.                     end ;
  135. {*
  136.  * Define the record to hold one entry of the list of files.
  137.  *}
  138.    FileEntryPtr= ^FileEntries ;
  139.    FileEntries = record
  140.                    Next: FileEntryPtr ;  { Next one in list }
  141.                    Prev: FileEntryPtr ;  { Previous one in the list }
  142.                    Name:    FileNames ;  { Name of file }
  143.                    Attr: Set of FileAttributes ;
  144.                    Size:      Integer ;  { Size of file [kB] }
  145.                    Mark:      Boolean ;  { File is marked }
  146.                  end ;
  147.  
  148. var
  149. {*
  150.  * Disk drive configuration.
  151.  *}
  152.    ConfiguredDrives: set of DriveNames ;  { Configured drives in CP/M }
  153.    FloppyDrives    : set of DriveNames ;  { Configured floppy drives }
  154.    DriveAttribute  : array[DriveNames] of DriveAttributes ;
  155. {*
  156.  * Attributes of the default CP/M drive.
  157.  *}
  158.    CpmCurrentDrive:            Byte ;  { BDOS default drive }
  159.    CpmDrive       :         Integer ;  { Target CP/M drive }
  160.    CpmDriveName   : FileDescriptors ;  { CP/M drive and user area }
  161.    CpmDriveAddress:         Integer ;  { Physical drive address }
  162. {*
  163.  * Attributes of the MS-DOS drive.
  164.  *}
  165.    MsdosDrive       :   Integer ;  { Drive with MS-DOS diskette }
  166.    MsdosDriveName   :      Char ;  { Drive with MS-DOS diskette }
  167.    MsdosDriveAddress:   Integer ;  { Physical address of MS-DOS drive }
  168.    MsdosDpb         :     ^DPBs ;  { DPB in use for MS-DOS disk }
  169.    MsdosFcb         :^MsdosFcbs ;  { FCB in use for MS-DOS file }
  170. {*
  171.  * Parameters of the currently active MS-DOS floppy disk.  These parameters
  172.  * are determined from the information in the bootsector at the time the
  173.  * MS-DOS drive is 'logged in'.
  174.  *}
  175.    SystemIdent      : String[8] ;  { Name if MS-DOS system }
  176.    FormatIdent      :      Byte ;  { Media descriptor }
  177.    BytesPerSector   :   Integer ;  { Size of physical sector [bytes] }
  178.    FcbsPerSector    :   Integer ;  { Size of physical sector [FCB's] }
  179.    RecordsPerSector :   Integer ;  { Size of physical sector [CP/M records] }
  180.    SectorsPerFat    :   Integer ;  { Size of FAT     [sectors] }
  181.    RecordsPerCluster:   Integer ;  { Size of cluster [records] }
  182.    SectorsPerCluster:   Integer ;  { Size of cluster [sectors] }
  183.    SectorsPerTrack  :   Integer ;  { Size of track   [sectors] }
  184.    SectorsPerDisk   :   Integer ;  { Size of disk    [sectors] }
  185.    ClustersPerDisk  :   Integer ;  { Size of disk   [clusters] }
  186.    FatsPerDisk      :   Integer ;  { Number of FATs }
  187.    SidesPerDisk     :   Integer ;  { Number of heads }
  188.    CylindersPerDisk :   Integer ;  { Number of cylinders }
  189.  
  190.    FirstFatSector    : Integer ;  { Ordinal of 1th sector of FAT }
  191.    FirstDataSector   : Integer ;  { Ordinal of 1th sector with user data }
  192.    RootDirectoryStart: Integer ;  { First sector of root directory }
  193.    RootDirectorySize : Integer ;  { Number of sectors in root directory }
  194. {*
  195.  * Directory search variables.
  196.  *}
  197.    DirectorySearchPos: SearchPositions ;  { Indication of search position }
  198.    DirectoryStartCls : Integer ;  { First cluster in dir chain }
  199.    DirectoryCluster  : Integer ;  { Current cluster in dir chain }
  200.    DirectoryStartSct : Integer ;  { First sector in current dir (cluster) }
  201.    DirectorySize     : Integer ;  { Number of sectors in current dir }
  202.    DirectorySector   : Integer ;  { Sector currently in dir buffer }
  203.    DirectoryOrdinal  : Integer ;  { Ordinal of FCB in dir sector }
  204.  
  205.    DirectoryNesting  : Integer ;  { Current directory nesting level }
  206.    MsdosPath: array[0..MsdosPathSize] of string[12] ;  { Full path name }
  207. {*
  208.  * File manager variables.
  209.  *}
  210.    DestinationOS  :          OSs ;  { Current destination OS }
  211.    SourceOS       :          OSs ;  { Current source OS }
  212.    HeadFileList   : FileEntryPtr ;  { Head of filelist }
  213.    TailFileList   : FileEntryPtr ;  { Tail of filelist }
  214.    SizeFileList   :      Integer ;  { Number of files in list }
  215.    FileEntry      : FileEntryPtr ;  { Current file in list }
  216.    FileIndex      :      Integer ;  { Ordinal of current file }
  217.    FileClass      :  FileClasses ;  { Type of file }
  218.    SizeTaggedFiles:      Integer ;  { Sum of sizes of tagged files }
  219.  
  220.    ACpmFile      :            File ;  { Some CP/M file }
  221.    ACpmFileName  : FileDescriptors ;  { Name of 'some' CP/M file }
  222.    AMsdosFileName: FileDescriptors ;  { Name of 'some' MS-DOS file }
  223.    CpmBinFillChar   :    Byte ;  { Character to fill up CP/M record }
  224.    CpmTxtFillChar   :    Byte ;  { Character to fill up CP/M record }
  225.    MsdosFillChar    :    Byte ;  { Character to fill up MS-DOS cluster }
  226.    CopyCpmFileAttr  : Boolean ;  { Copy CP/M file attributes to MS-DOS file }
  227.    CopyMsdosFileAttr: Boolean ;  { Copy MS-DOS file attributes to CP/M file }
  228.  
  229.    MsdosDate :     Integer ;  { Current date, MS-DOS formatted }
  230.    TodaysDate: DateStrings ;  { Current date, numeric string }
  231. {*
  232.  * Error handling.
  233.  *}
  234.    ErrorDetected: Boolean ;  { Some error has been detected }
  235.    ErrorIndex   : Integer ;  { Current stacking level of errors }
  236.    ErrorMessage : array[0..ErrorStackSize] of ErrorMessages ;
  237. {*
  238.  * Buffer areas.
  239.  *}
  240.    ClusterBuffer: array[0..ClusterSize] of Byte ;  { Buffer for one cluster }
  241.    DirBuffer    : array[0.. SectorSize] of Byte ;  { Directory buffer }
  242.    FatBuffer    : array[0..    FatSize] of Byte ;  { File Assignment Table }
  243.    SavedDpb     :                          DPBs ;  { Save area for CP/M DPB }
  244.  
  245. {*
  246.  * Define the limits of the memory area allocated to the global variables.
  247.  * These limits are used to preset all the global variables in a fast way.
  248.  *}
  249.    FirstGlobalVariable: Byte ;  { Lowest address ! }
  250.    LastGlobalVariable : Byte absolute ConfiguredDrives;  { Highest address ! }
  251.  
  252. const
  253. {*
  254.  * Define a skeletal MS-DOS DPB, which is enough to read the boot sector.
  255.  * The fields SPT, BLM as well as all the extension fields need to be set
  256.  * lateron according to the actual MS-DOS disk format.
  257.  *}
  258.    SkeletDpb: DPBs =
  259.    ( XLT:(01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,
  260.           21,22,23,24,25,26) ;
  261.      SPT: 72 ; BSH:$02 ; BLM:$03 ; EXM:$01 ; DSM:180 ; DRM: 64 ;
  262.      ALM:128 ; CKS:$00 ; OFF: 00 ; FNO:$07 ; DDS:$A0 ; PDA:$00 ;
  263.      TFC: 00 ; PSS: 04 ; PCD: 40 ; PST: 09 ) ;
  264.  
  265.  
  266. {* -------------------------------------------------------------------------
  267.  *                E L E M E N T A R Y   C O N S O L E   I / O
  268.  * ------------------------------------------------------------------------- *}
  269.  
  270. procedure Continue ;
  271. {*
  272.  * Ask the attention of the user and the permission to go ahead.
  273.  *}
  274. var
  275.    SomeChar: Char ;  { Character read from keyboard }
  276. begin
  277.    Write( ^G'Press <Return> to continue.' ) ;
  278.    repeat
  279.      Read( Kbd, SomeChar ) ;
  280.    until SomeChar=Cr ;
  281. end ;  { of Continue }
  282.  
  283. function ReadYesNoAnswer( Question: ErrorMessages ) : Char ;
  284. {*
  285.  * Read a Y(es) or N(o) answer on the given question.
  286.  *}
  287. var
  288.    Answer: Char ;  { Answer read }
  289. begin
  290.    Write( Question, '? ' ) ;
  291.    repeat
  292.      Read ( Kbd, Answer ) ;
  293.      Answer:= UpCase( Answer ) ;
  294.    until Answer in ['N','Y'] ;
  295.    Write( Answer, ' ' ) ;
  296.    ReadYesNoAnswer:= Answer ;
  297. end ;  { of ReadYesNoAnswer }
  298.  
  299.  
  300. {* -------------------------------------------------------------------------
  301.  *                       E R R O R   H A N D L I N G
  302.  * ------------------------------------------------------------------------- *}
  303.  
  304. {*
  305.  * The following ideas with respect to error handling are incorporated
  306.  * in this program:
  307.  *
  308.  * Each basic procedure, that is each procedure that does not invoke another
  309.  * pascal procedure, that handles disk I/O, flags an error when detected and
  310.  * it returns immediatly to the calling procedure.  A basic function will
  311.  * pass some sort of end indication after an error has been detected.
  312.  *
  313.  * Each non-basic procedure checks a global errorflag to see if an error has
  314.  * been detected by a basic procedure.  It will prepend its name to the error-
  315.  * message and return immediatly.
  316.  *
  317.  * At the top level procedure, errors, if any, are reported to the user.  Once
  318.  * reported the error condition is cleared.  Thus after an error is detected,
  319.  * the operation is terminated immediatly and the error is reported.
  320.  * However, it may be necessary to clean up the remnants of the partially
  321.  * completed operation in an error-free state.  For this purpose a stack of
  322.  * errors is introduced.  During the clean-up the error status is saved and it
  323.  * is restored once the cleaning-up is done.  In this way, the errors detected
  324.  * during clean-up can be handled in the normal fashion.
  325.  *}
  326.  
  327. procedure BuildErrorTrace( Name: ErrorMessages ) ;
  328. {*
  329.  * Add the name of a procedure in front of the current errormessage.
  330.  * In this way an elementary trace mechanism is implemented.
  331.  *}
  332. begin
  333.    ErrorMessage[ErrorIndex]:= Name + ErrorMessage[ErrorIndex] ;
  334. end ;  { of BuildErrorTrace }
  335.  
  336. procedure ClearError ;
  337. {*
  338.  * Clear the current error message.  This procedure will be called if there
  339.  * is a possibility to recover the error.
  340.  *}
  341. begin
  342.    ErrorDetected           := False ;
  343.    ErrorMessage[ErrorIndex]:=    '' ;
  344. end ;  { of ClearError }
  345.  
  346. procedure FlagError( Details: ErrorMessages ) ;
  347. {*
  348.  * Signal the detection of an error in the global error variables.  However,
  349.  * do NOT overwrite a pending errormessage: The first one is probably the
  350.  * most descriptive/meaningfull one.
  351.  *}
  352. begin
  353.    if not ErrorDetected then
  354.     begin
  355.      ErrorDetected:= True ;
  356.      ErrorMessage[ErrorIndex]:= Details ;
  357.     end ;
  358. end ;  { of FlagError }
  359.  
  360. procedure PopErrorMessage ;
  361. {*
  362.  * 'Pop' the previous error message, if any, from the error message stack
  363.  * and continue in that errorstate.
  364.  *}
  365. begin
  366.    if ErrorIndex>0 then
  367.     begin
  368.      ErrorIndex   := 0 ;
  369.      ErrorDetected:= Length(ErrorMessage[0])<>0 ;
  370.     end ;
  371. end ;  { of PopErrorMessage }
  372.  
  373. procedure PushErrorMessage ;
  374. {*
  375.  * 'Push' the current error message onto the error message stack.  Search
  376.  * for and activate an unused entry in the stack.  This procedure should be
  377.  * invoked whenever another basic MS-DOS function is to be executed.
  378.  *}
  379. begin
  380.    repeat
  381.      ErrorIndex   := Succ( ErrorIndex ) ;
  382.      ErrorDetected:= Length(ErrorMessage[ErrorIndex])<>0 ;
  383.    until (ErrorIndex=ErrorStackSize) or (not ErrorDetected) ;
  384. end ;  { of PushErrorMessage }
  385.  
  386. procedure ReportError ;
  387. {*
  388.  * Display the stack of errormessages and remove them from the stack.  The
  389.  * errorstatus is cleared.
  390.  *}
  391. var
  392.    I: Integer ;  { Loop control variable }
  393. begin
  394.    ErrorDetected:= False ;  { No error(s) found yet in the stack }
  395.  
  396.    for I:= 0 to ErrorStackSize do
  397.      if Length(ErrorMessage[I])>0 then
  398.       begin
  399.        if not ErrorDetected then
  400.          Write( ^M^J^J ) ;
  401.        WriteLn( 'Error in ', ErrorMessage[I], '. ' ) ;
  402.        ErrorMessage[I]:=   '' ;
  403.        ErrorDetected  := True ;  { An error has been found in the stack }
  404.       end ;  { of if/for }
  405.  
  406.    if ErrorDetected then
  407.     begin
  408.      ErrorDetected:= False ;
  409.      Continue ;
  410.     end ;  { of if }
  411.    ErrorIndex:= 0 ;
  412. end ;  { of ReportError }
  413.  
  414.