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