home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / TURBOPAS / EXTFN.ARK / EXTFN.UNT < prev    next >
Text File  |  1989-09-27  |  19KB  |  528 lines

  1. {.L-}  { Suppress listing by LISTT }
  2. {*
  3.  * --------------------------------------------------------------------
  4.  *         E X T E N D E D   F I L E   N A M E S   U N I T
  5.  * --------------------------------------------------------------------
  6.  *
  7.  * With this 'unit' the possibility to specify extended file names in
  8.  * Turbo Pascal programs is created.  An extended file includes also
  9.  * the user number of the file, thus an extended file name looks like:
  10.  *    <Disk><User_Number>:<Primary_Name>.<Secondary_Name>
  11.  * The extended file name can be an ambigious file name. However neither
  12.  * the disk number nor the user number can be 'wildcards'.
  13.  *
  14.  * The implementation does not contain any hardware dependencies.
  15.  *
  16.  *               I N T E R F A C E   S E C T I O N
  17.  *}
  18. type
  19.    FileTypes      = ( DiskFile,        { Disk file }
  20.                       Device   ) ;     { Logical device }
  21.    FileNameTypes  = ( DUNE_Format,     { Extended file name }
  22.                        DNE_Format,     { Full CP/M file name }
  23.                         NE_Format ) ;  { Only primary & secondary name }
  24.    FullFileNames  = string[16] ;       { Extended file name }
  25.  
  26.    FileDescriptors= record
  27.                       FileType: FileTypes ;  { File type }
  28.                       Drive   :      Byte ;  { Drive number }
  29.                       User    :      Byte ;  { User number }
  30.                       Name    : string[8] ;  { Primary name }
  31.                       Ext     : string[3] ;  { Secondary name }
  32.                     end ;
  33.  
  34. {
  35.  function  ExpandFileName( var FileDesc : FileDescriptors ;
  36.                                NameType : FileNameTypes ) : FullFileNames ;
  37.  
  38.  procedure InitFileNameUnit ;
  39.  
  40.  procedure RegisterFile  ( var FileDesc : FileDescriptors ;
  41.                            var SomeFile ) ;
  42.  
  43.  function  SameName      ( var FileDesc1: FileDescriptors ;
  44.                            var FileDesc2: FileDescriptors ,
  45.                                NameType : FileNameTypes ) : Boolean ;
  46.  
  47.  procedure SplitFileName ( var FileDesc : FileDescriptors ;
  48.                                FileName : FullFileNames ) ;
  49.  
  50.  procedure UnInitFileNameUnit ;
  51.  
  52.  procedure UnRegisterFile( var SomeFile ) ;
  53. }
  54.  
  55. {*
  56.  *         I M P L E M E N T A T I O N   S E C T I O N
  57.  *}
  58. const
  59.    MaxRXFCnt     =  3 ;  { Maximum number of registered FCBs - 1 }
  60.  
  61. type
  62.    JumpStructures = record
  63.                       Instruction :    Byte ;  { Jump instruction }
  64.                       Address     : Integer ;  { Jump address }
  65.                     end ;
  66.    RegisteredFCBs = array[0..MaxRXFCnt] of record
  67.                       FCBAddress  : Integer ;  { Address of FCB }
  68.                       UserNumber  :    Byte ;  { Associated user }
  69.                     end ;
  70. var
  71.    BDosEntry : JumpStructures ;  { Jump into original BDos }
  72.    RXFCnt    :           Byte ;  { Number of Registered eXtended FCBs }
  73.    RXFLst    : RegisteredFCBs ;  { List of registered extended FCBs }
  74.  
  75. procedure OwnBDos ;
  76. {*
  77.  * OwnBDos is a front-end to the standard BDos. Through a modification
  78.  * of the jump vector, this procedure is called by the pascal runtime
  79.  * routines.  OwnBDos implements the extended file names: before each
  80.  * file operation, the user number associated with the file is selected
  81.  * and upon completion the original user number is restored.
  82.  *
  83.  * The following BDos functions are handled by this procedure:
  84.  *   15 - Open File
  85.  *   16 - Close File
  86.  *   19 - Delete File
  87.  *   20 - Read Sequential
  88.  *   21 - Write Sequential
  89.  *   22 - Make File
  90.  *   33 - Read Random
  91.  *   34 - Write Random
  92.  *   35 - Compute File Size
  93.  *}
  94. var
  95.    CurUsr : Byte ;  { Save area of user number }
  96. begin
  97.    InLine(
  98.      $3A /      RXFCnt / {LD   A,(RXFCNT) Number of registred FCB's }
  99.      $B7 /               {OR   A          Set condition codes}
  100.      $28 / $19 /         {JR   Z,EXT010   Exit if none registred }
  101.      $79 /               {LD   A,C        Function code }
  102.      $D6 / $0F /         {SUB  15         Compare with lower bound, 15 }
  103.      $38 / $14 /         {JR   C,EXT010   Exit if non-disk function }
  104.      $D6 / $02 /         {SUB  16+1-15    Compare with upper bound, 16 }
  105.      $38 / $13 /         {JR   C,EXT020   Brif a disk function }
  106.      $D6 / $02 /         {SUB  19-16-1    Compare with lower bound, 19 }
  107.      $38 / $0C /         {JR   C,EXT010   Exit if non-disk function }
  108.      $D6 / $04 /         {SUB  22+1-19    Compare with upper bound, 22 }
  109.      $38 / $0B /         {JR   C,EXT020   Brif a disk function }
  110.      $D6 / $0A /         {SUB  33-22-1    Compare with lower bound, 33 }
  111.      $38 / $04 /         {JR   C,EXT010   Exit if non-disk function }
  112.      $D6 / $03 /         {SUB  35+1-33    Compare with upper bound, 35 }
  113.      $38 / $03 /         {JR   C,EXT020   Brif a disk function }
  114.      $C3 /   BDosEntry / {JP   BDOS       Enter BDOS }
  115.      $FD / $21 /RXFLst / {LD   IY,RXFLST  List of registered FCB's }
  116.      $3A /      RXFCnt / {LD   A,(RXFCNT) Number of registered FCB's }
  117.      $47 /               {LD   B,A        Move number }
  118.      $FD / $6E / $00   / {LD   L,(IY+0)   LSB of registered FCB address }
  119.      $FD / $66 / $01   / {LD   H,(IY+1)   MSB of registered FCB address }
  120.      $B7 /               {OR   A          Clear carry flag }
  121.      $ED / $52 /         {SBC  HL,DE      Compare with supplied FCB address }
  122.      $28 / $0B /         {JR   Z,EXT030   Brif FCB found in list }
  123.      $FD / $23 /         {INC  IY         Move pointer to next entry }
  124.      $FD / $23 /         {INC  IY }
  125.      $FD / $23 /         {INC  IY }
  126.      $10 / $ED /         {DJNZ EXT025     Brif not at end of list }
  127.      $C3 /   BDosEntry / {JP   BDOS       Exit if non-registered FCB }
  128.      $C5 /               {PUSH BC         Save BDos function code }
  129.      $D5 /               {PUSH DE         Save FCB address }
  130.      $0E / $20 /         {LD   C,020H     Function= Get/Set_User_Number }
  131.      $1E / $FF /         {LD   E,0FFH     Select Get_User_Number function }
  132.      $CD /   BDosEntry / {CALL BDOS       Invoke BDos }
  133.      $32 /      CurUsr / {LD   (CURUSR),A Save current user number }
  134.      $0E / $20 /         {LD   C,020H     Function= Get/Set_User_Number }
  135.      $FD / $5E / $02   / {LD   E,(IY+2)   Load requested user number }
  136.      $CD /   BDosEntry / {CALL BDOS       Invoke BDos }
  137.      $D1 /               {POP  DE         Restore address of FCB }
  138.      $C1 /               {POP  BC         Restore BDos function code }
  139.      $CD /   BDosEntry / {CALL BDOS       Invoke BDos }
  140.      $F5 /               {PUSH AF         Save return code }
  141.      $0E / $20 /         {LD   C,020H     Function=Get/Set_User_Number }
  142.      $3A /      CurUsr / {LD   A,(CURUSR) Original user number }
  143.      $5F /               {LD   E,A         }
  144.      $CD /   BDosEntry / {CALL BDOS       Invoke BDos }
  145.      $F1 ) ;             {POP  AF         Restore return code from disk }
  146. end ;  { of OwnBDos }
  147.  
  148.  
  149. function GetUserNumber : Integer ;
  150. {*
  151.  * GetUserNumber - Retrieve the user number. The returned number is in
  152.  *                 the range [1,16]!
  153.  *}
  154. const
  155.    GetSetUserNmbr= 32 ;  { BDos function: get or set the user number }
  156. begin
  157.    GetUserNumber:= Succ( BDos( GetSetUserNmbr, $00FF ) ) ;
  158. end ;  { of GetUserNumber }
  159.  
  160. function GetDiskNumber : Integer ;
  161. {*
  162.  * GetDiskNumber - Retrieve the current disk number. The returned number
  163.  *                 is in the range [1,16]!
  164.  *}
  165. const
  166.    GetCurrentDisk= 25 ;  { BDos function: return ordinal of current disk }
  167. begin
  168.    GetDiskNumber:= Succ( BDos( GetCurrentDisk ) ) ;
  169. end ;  { of GetDiskNumber }
  170.  
  171. function ExpandFileName( var FileDesc: FileDescriptors ;
  172.                              NameType: FileNameTypes ) : FullFileNames ;
  173. {*
  174.  * ExpandFileName - Create the file name in a string from an (extended)
  175.  * file descriptor.  A 'current' specification of both the drive and
  176.  * the user are replaced by their actual values.
  177.  *}
  178. var
  179.    Result : FullFileNames ;  { Result of function }
  180. begin
  181.    with FileDesc do
  182.     begin
  183.      if FileType=Device then
  184.        Result:= Name
  185.      else  { if FileType=Diskfile then }
  186.       begin
  187.        Result:= '' ;
  188.        if NameType=DUNE_Format then
  189.          if User=0 then
  190.            Str( Pred(GetUserNumber), Result )
  191.          else
  192.            Str( Pred(         User), Result ) ;
  193.  
  194.        if NameType<>NE_Format then
  195.          if Drive=0 then
  196.            Result:= Chr(GetDiskNumber + Pred(Ord('A'))) + Result + ':'
  197.          else
  198.            Result:= Chr(Drive         + Pred(Ord('A'))) + Result + ':' ;
  199.  
  200.        Result:= Result + Name + '.' + Ext ;
  201.       end ;  { of if }
  202.     end ;  { of with }
  203.  
  204.    ExpandFileName:= Result ;
  205. end ;  { of ExpandFileName }
  206.  
  207. procedure RegisterFile( var FileDesc: FileDescriptors ; var FIB ) ;
  208. {*
  209.  * RegisterFile - Register an extended file: the full name is given in
  210.  *                the descriptor and the Pascal FileInterfaceBlock (FIB)
  211.  *                specifies which FCB will be used.
  212.  *
  213.  * This procedure is needed to effectuate the user number specified in
  214.  * the file descriptor.
  215.  *}
  216. var
  217.    FIBFCB : Integer ;  { Address of FCB within FIB }
  218.    I      : Integer ;  { Loop control variable }
  219. begin
  220. {*
  221.  * Register only disk files: logical device names do not have a user number
  222.  * associated with them.
  223.  *}
  224.    if FileDesc.FileType=DiskFile then
  225.     begin
  226.      FIBFCB:= Addr(FIB ) + 12 ;
  227. {*
  228.  * Locate either a free entry or an entry which specifies the same FCB.
  229.  * The RegisterFile performs thus implicitly an 'UnRegisterFile'.
  230.  *}
  231.      I:= -1 ;
  232.      repeat
  233.        I:=Succ(I)
  234.      until (I=RXFCnt) or (RXFLst[I].FCBAddress=FIBFCB) ;
  235.  
  236.      if I<=MaxRXFCnt then
  237.       begin
  238.        with RXFLst[I] do
  239.         begin
  240.          FCBAddress:= FIBFCB ;
  241.          if FileDesc.User=0 then
  242.            UserNumber:= Pred( GetUserNumber )
  243.          else
  244.            UserNumber:= Pred( FileDesc.User ) ;
  245.         end ;  { of with }
  246.        if I=RXFCnt then
  247.          RXFCnt:= Succ( RXFCnt ) ;
  248.       end
  249.      else
  250.        Halt ;  { Fatal error : Table Overflow }
  251.    end ;  { of if }
  252. end ;  { of RegisterFile }
  253.  
  254. function SameName( var FileDesc1, FileDesc2 : FileDescriptors ;
  255.                        NameType             : FileNameTypes ) : Boolean ;
  256. {*
  257.  * SameName - Determine whether two ambigious (!) file descriptors specify
  258.  *            the same file name.
  259.  *
  260.  * The comparison algorithm classifies the characters from the file
  261.  * names into five classes: '?', '.'. ':', 'other character' and
  262.  * 'end of name'.  Using this classification, the algorithm is
  263.  * specified by the following state table:
  264.  *
  265.  *        |  ?  |  .  |  :  | Oth | End    Description of actions
  266.  *   -----+-----+-----+-----+-----+-----   -------------------------
  267.  *     ?  |  0  |  1  |  1  |  0  |  1     0 : Advance both pointers
  268.  *   -----+-----+-----+-----+-----+-----   1 : Advance pointer # 1
  269.  *     .  |  2  |  0  |  3  |  3  |  1     2 : Advance pointer # 2
  270.  *   -----+-----+-----+-----+-----+-----   3 : Mismatch & Exit
  271.  *     :  |  2  |  3  |  0  |  3  |  1     4 : Compare
  272.  *   -----+-----+-----+-----+-----+-----       if mismatch then (3)
  273.  *    Oth |  0  |  3  |  3  |  4  |  3         if match    then (0)
  274.  *   -----+-----+-----+-----+-----+-----   5 : Match & Exit
  275.  *    End |  2  |  2  |  2  |  3  |  5
  276.  *   -----+-----+-----+-----+-----+-----
  277.  *}
  278. const
  279.    SintJuttemis = False ;
  280.  
  281. type
  282.    Classes = ( Wildcard, Dot, Colon, Other, EndOfName ) ;
  283.    Actions = ( Act0, Act1, Act2, Act3, Act4, Act5 ) ;
  284.  
  285. const
  286.    StateTable : array[Classes] of array[Classes] of Actions =
  287.                 ( ( Act0, Act1, Act1, Act0, Act1 ),
  288.                   ( Act2, Act0, Act3, Act3, Act1 ),
  289.                   ( Act2, Act3, Act0, Act3, Act1 ),
  290.                   ( Act0, Act3, Act3, Act4, Act3 ),
  291.                   ( Act2, Act2, Act2, Act3, Act5 ) ) ;
  292.  
  293. var
  294.    File1 : FullFileNames ;  { Expanded name of first file }
  295.    File2 : FullFileNames ;  { Expanded name of second file }
  296.    Index1:       Integer ;  { Index in File1 name string }
  297.    Index2:       Integer ;  { Index in File2 name string }
  298.    Action:       Actions ;  { Action for current character pair }
  299.  
  300.  function ClaNC( var FileName : FullFileNames ;
  301.                  var Index    :       Integer ) : Classes ;
  302.  {*
  303.   * ClaNC - CLAssify_Next_Character : Extract the next character from the
  304.   *         name of the file and classify it.
  305.   *}
  306.  begin
  307.     if Index>Length(FileName) then
  308.       ClaNC:= EndOfName
  309.     else
  310.      begin
  311.       case FileName[Index] of
  312.         '.' : ClaNC:= dot ;
  313.         ':' : ClaNC:= colon ;
  314.         '?' : ClaNC:= WildCard ;
  315.       else
  316.         ClaNC:= Other ;
  317.       end ;  { of case }
  318.      end ;  { of if }
  319.  end ;  { of ClaNC }
  320.  
  321. begin
  322.    File1:= ExpandFileName( FileDesc1, NameType ) ;
  323.    File2:= ExpandFileName( FileDesc2, NameType ) ;
  324.  
  325.    Index1:= 1 ;
  326.    Index2:= 1 ;
  327.    repeat
  328.      Action:= StateTable[ ClaNC(File1,Index1), ClaNC(File2,Index2) ] ;
  329.      case Action of
  330.        Act0 : begin
  331.                Index1:= Succ( Index1 ) ;
  332.                Index2:= Succ( Index2 ) ;
  333.               end ;  { of case Act0 }
  334.        Act1 : begin
  335.                Index1:= Succ( Index1 ) ;
  336.               end ;  { of case Act1 }
  337.        Act2 : begin
  338.                Index2:= Succ( Index2 ) ;
  339.               end ;  { of case Act2 }
  340.        Act3 : begin
  341.                SameName:= False ;  { Set function result }
  342.                Exit ;              { Return to caller }
  343.               end ;  { of case Act3 }
  344.        Act4 : begin
  345.                if File1[Index1]=File2[Index2] then
  346.                 begin
  347.                  Index1:= Succ( Index1 ) ;
  348.                  Index2:= Succ( Index2 ) ;
  349.                 end
  350.                else
  351.                 begin
  352.                  SameName:= False ;
  353.                  Exit ;
  354.                 end ;  { of if }
  355.               end ;  { of case Act4 }
  356.        Act5 : begin
  357.                SameName:= True ;  { Set function result }
  358.                Exit ;             { Return to caller }
  359.               end ;  { of case Act5 }
  360.      end ;  { of case }
  361.    until SintJuttemis ;
  362. end ;  { of SameName }
  363.  
  364. procedure SplitFileName( var FileDesc: FileDescriptors ;
  365.                              FileName: FullFileNames ) ;
  366. {*
  367.  * SplitFileName - Split up the extended name of a file into its components.
  368.  *                 The wildcard character '*' is expanded to multiple '?',
  369.  *                 until the end of the field.
  370.  *}
  371. type
  372.    SomeStrings = string[16] ;  { Some string which is big enough }
  373. var
  374.    DevName    : string[5] ;  { (Possible) device name }
  375.    I          :   Integer ;  { Pointer to field separator }
  376.    Result     :   Integer ;  { Result of string-to-integer conversion }
  377.    ReturnCode :   Integer ;  { Return code from 'Val' procedure }
  378.  
  379.  function Trim( SomeString : SomeStrings ) : SomeStrings ;
  380.  {*
  381.   * Trim - Remove the leading and the trailing spaces from a string and
  382.   *        expand the '*' wild character.
  383.   *}
  384.  var
  385.     I : Integer ;  { Position of '*' in string }
  386.  begin
  387.  {*
  388.   * Remove the leading blank spaces .
  389.   *}
  390.     while (Length(SomeString)>0) and (SomeString[1]=' ') do
  391.       Delete( SomeString, 1, 1 ) ;
  392.  {*
  393.   * Remove the trailing blank spaces.
  394.   *}
  395.     while (Length(SomeString)>0) and (SomeString[Length(SomeString)]=' ') do
  396.       Delete( SomeString, Length(SomeString), 1 ) ;
  397.  {*
  398.   * Change all lowercase characters into uppercase characters.
  399.   *}
  400.     if Length(SomeString)>0 then
  401.       for I:= 1 to Length(SomeString) do
  402.         SomeString[I]:= UpCase(SomeString[I]) ;
  403.  {*
  404.   * Expand the first '*' wildcharacter into multiple '?' wild characters,
  405.   * filling up the field.  Truncation at the assignment of the function value
  406.   * is assumed in this code, as the maximum length of SomeString isn't known.
  407.   *}
  408.     I:= Pos( '*', SomeString ) ;
  409.     if I>0 then
  410.       SomeString:= Copy( SomeString, 1, Pred(I) ) + '????????' ;
  411.  
  412.     Trim:= SomeString ;
  413.  end ;  { of Trim }
  414.  
  415. begin
  416.    FileDesc.FileType := DiskFile ;
  417.    FileDesc.Drive    :=  0 ;
  418.    FileDesc.User     :=  0 ;
  419.    FileDesc.Name     := '' ;
  420.    FileDesc.Ext      := '' ;
  421.  
  422. {*
  423.  * Check for a name of a logical device.
  424.  *}
  425.    DevName:= Trim( FileName ) ;
  426.    if Length(DevName)=4 then
  427.      if DevName[4]=':' then
  428.        if Pos( DevName, 'CON:TRM:KBD:LST:AUX:USR:' )<>0 then
  429.         begin
  430.          FileDesc.FileType:= Device ;
  431.          FileDesc.Name    := Trim(FileName) ;
  432.          Exit ;
  433.         end ;  { of if/if/if }
  434.  
  435. {*
  436.  * Extract the secondary name from the file name.
  437.  *}
  438.    I:= Pos( '.', FileName ) ;
  439.    if I>0 then
  440.     begin
  441.      FileDesc.Ext:= Trim( Copy(FileName, Succ(I), 3) ) ;
  442.      FileName:= Copy( FileName, 1, Pred(I) ) ;
  443.     end ;  { of if }
  444. {*
  445.  * Extract the primary name from the file name.
  446.  *}
  447.    I:= Pos( ':', FileName ) ;
  448.    FileDesc.Name:= Trim( Copy(FileName, Succ(I), 8) ) ;
  449. {*
  450.  * Extract the drive name and the user number from the file name.
  451.  *}
  452.    if I>1 then
  453.     begin
  454.      FileName:= Copy( FileName, 1, Pred(I) ) ;
  455. {*
  456.  * Look for the drive name.
  457.  *}
  458.      if FileName[1] in ['A'..'P','a'..'p'] then
  459.       begin
  460.        FileDesc.Drive:= Succ( Ord(UpCase(FileName[1])) - Ord('A') ) ;
  461.        FileName:= Copy( FileName, 2, I ) ;
  462.       end ;  { of if }
  463. {*
  464.  * Look for the user number.
  465.  *}
  466.      if Length(FileName)>0 then
  467.       begin
  468.        Val( FileName, Result, ReturnCode ) ;
  469.        if ReturnCode=0 then
  470.          FileDesc.User:= Succ(Result) ;
  471.       end ;  { of if }
  472.     end ;  { of if }
  473. end ;  { of SplitFileName }
  474.  
  475. procedure UnRegisterFile( var FIB ) ;
  476. {*
  477.  * UnRegisterFile - Remove the registration of file with the given FIB
  478.  *                  from the list.
  479.  *}
  480. var
  481.    FIBFCB : Integer ;  { Address of FCB within FIB }
  482.    I      : Integer ;  { Loop control variable }
  483. begin
  484.    FIBFCB:= Addr(FIB ) + 12 ;
  485. {*
  486.  * Locate the entry which specifies the same FCB.
  487.  *}
  488.    I:= -1 ;
  489.    repeat
  490.      I:=Succ(I)
  491.    until (I=RXFCnt) or (RXFLst[I].FCBAddress=FIBFCB) ;
  492.  
  493.    if I<RXFCnt then  { remove the located entry }
  494.     begin
  495.      RXFCnt:= Pred(RXFCnt) ;
  496.      while I<RXFCnt do  { shift the succeeding entries }
  497.       begin
  498.        RXFLst[I]:= RXFLst[Succ(I)] ;
  499.        I        :=        Succ(I)  ;
  500.       end ;  { of while }
  501.     end ;  { of if }
  502. end ;  { of UnRegisterFile }
  503.  
  504. procedure InitFileNameUnit ;
  505. {*
  506.  * Install the BDos extension (filter).
  507.  *}
  508. var
  509.    BDosAddress : Integer absolute $0006 ;  { Address of BDos entry point }
  510. begin
  511.    BDosEntry.Instruction:=         $C3 ;  { Jump instruction }
  512.    BDosEntry.Address    := BDosAddress ;  { Save address of BDos entry point }
  513.    BDosAddress:= Addr( OwnBDos ) ;        { Install own BDos extension }
  514.  
  515.    RXFCnt:= 0 ;
  516. end ;  { of InitFileNameUnit }
  517.  
  518. procedure UnInitFileNameUnit ;
  519. {*
  520.  * Restore the original BDos entry, thus removing the BDos extension.
  521.  *}
  522. var
  523.    BDosAddress : Integer absolute $0006 ;  { Address of BDos entry point }
  524. begin
  525.    BDosAddress:= BDosEntry.Address ;  { Restore original BDos entry point }
  526. end ;  { of UnInitFileNameUnit }
  527. {.L+}
  528.