home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PROGRAMS / UTILS / MEMORIA / OWNER152.ZIP / OWNER.ASM next >
Encoding:
Assembly Source File  |  1987-03-13  |  27.8 KB  |  649 lines

  1. PAGE ,132
  2. TITLE Cluster Owner Program, Version 1.52, 13-Mar-1987
  3.  
  4. ;
  5. ; Written By Steven Georgiades
  6. ;
  7. ; Cluster Owner Program
  8. ;   Will respond with the name of the file that owns the specified cluster.
  9. ;
  10. ;       If you are using this program and find it of value, your
  11. ;       contribution in any amount ($10.00 suggested) will be greatly
  12. ;       appreciated.  Makes checks payable to Steven M. Georgiades.
  13. ;               Thank you.
  14. ;
  15. ;       If you have any questions or comments about this or any other
  16. ;       SMG program, call or write:
  17. ;
  18. ;               Steven M. Georgiades
  19. ;               SMG Software
  20. ;               701-H South Hayward Street
  21. ;               Anaheim, CA 92804
  22. ;
  23.  
  24. CODE      SEGMENT BYTE PUBLIC 'CODE'
  25.  
  26.           ASSUME  CS:CODE,DS:CODE,ES:CODE,SS:CODE
  27.  
  28.           ORG     5CH
  29.  
  30. FCB       LABEL   BYTE
  31.  
  32.           ORG     80H
  33.  
  34. PARAM     LABEL   BYTE
  35.  
  36.           ORG     100H
  37.  
  38. OWNER:    JMP     BEGIN
  39.  
  40. CRLF      DB      13,10,"$"
  41. DIGIT     DB      "0123456789ABCDEF"
  42. PARM_ERR  DB      "Illegal Parameter!",7,13,10,"$"
  43. READERR   DB      "Error Reading Drive X:",7,13,10,"$"
  44. SIGNON    DB      "Cluster Owner Program, Version 1.52",13,10
  45.           DB      "SMG Software",13,10
  46.           DB      "(C) Copyright 1986,1987 Steven Georgiades",13,10,10,"$"
  47. USAGE     DB      "Usage:",13,10,10
  48.           DB      "  OWNER [n]",13,10,10
  49.           DB      "    n = Cluster Number to Check",13,10,10,"$"
  50. CLUSTMSG  DB      "Cluster XXXXX $"
  51. OWNERMSG  DB      "is Owned by $"
  52. BADMSG    DB      "is Marked as Bad",13,10,"$"
  53. FREEMSG   DB      "is not is Use by any File",13,10,"$"
  54. INVALID   DB      "does not Exist!",7,13,10,"$"
  55. LOSTMSG   DB      "Appears to be Lost!",7,13,10,"$"
  56. RESVMSG   DB      "is Reserved",13,10,"$"
  57.  
  58. CLSTSEC   DW      ?
  59. CLSTTOT   DW      ?
  60. CLUST     DW      ?
  61. DIR_LEN   DW      ?
  62. DIRBUF    DW      ?
  63. DIRSEC    DW      ?
  64. DRIVE     DB      ?
  65. EOF       DW      0FF8H
  66. FATSEC    DW      ?
  67. FATSIZE   DB      3
  68. RDIR_LEN  DW      ?
  69. SECSIZE   DW      ?
  70. STARTSEC  DW      ?
  71.  
  72. DIRNAME   DB      14 DUP(0)
  73. FILESPEC  DB      "X:\"
  74. PATH      DB      "$",79 DUP(0)
  75. FILENAME  DB      14 DUP(0)
  76.  
  77. BEGIN:    MOV     AH,9                          ; Output Sign-On Message
  78.           MOV     DX,OFFSET SIGNON
  79.           INT     21H
  80.           MOV     AH,19H                        ; Get Default Drive Number
  81.           INT     21H
  82.           MOV     DRIVE,AL                      ;   and Save
  83.           MOV     SI,OFFSET PARAM               ; Set up Pointer to Parameter
  84.           LODSB                                 ; Read Parameter Length
  85.           CMP     AL,2
  86.           JNB     GET_PARM
  87.           MOV     DX,OFFSET USAGE
  88.           JMP     ERROUT
  89. GET_PARM: CBW
  90.           MOV     BX,AX
  91.           MOV     BYTE PTR [SI][BX],0           ; Terminate Parameter String
  92. STRIP:    LODSB                                 ; Strip Off Leading Whitespace
  93.           CMP     AL,' '
  94.           JE      STRIP
  95.           CMP     AL,9
  96.           JE      STRIP
  97.           OR      AL,AL                         ; If End-of-Parameter,
  98.           JZ      RD_BOOT                       ;   Continue Proccessing
  99.           CMP     AL,'/'                        ; If Switch, Process
  100.           JE      SWITCH
  101.           DEC     SI                            ; ReUse Last Character
  102.           CALL    GET_WORD                      ; Read Cluster Number (Hex)
  103.           JE      PARMERR
  104.           MOV     CLUST,DX                      ; Save Cluster Number
  105.           JMP     SHORT STRIP                   ; Get Next Parameter
  106. PARMERR:  MOV     DX,OFFSET PARM_ERR            ; Output Parameter Error Message
  107.           JMP     ERROUT
  108. SWITCH:   LODSB                                 ; Get Drive Letter
  109.           SUB     AL,'A'                        ; Convert to Drive Number 
  110.           MOV     DRIVE,AL                      ; Save Drive Number
  111.           JMP     SHORT STRIP                   ; Get Next Paramter
  112. RD_BOOT:  MOV     AL,DRIVE                      ; Read Boot Record
  113.           MOV     CX,1
  114.           MOV     DX,0
  115.           MOV     BX,OFFSET FATBUF
  116.           INT     25H
  117.           JNC     BOOT_OK
  118.           JMP     RDERROR                       ; If Error, Say So
  119. BOOT_OK:  POPF
  120.           MOV     AX,FATBUF[11]                 ; Read Sector Size
  121.           MOV     SECSIZE,AX                    ;   and Save
  122.           MOV     AL,BYTE PTR FATBUF[13]        ; Read Sectors per Cluster
  123.           XOR     AH,AH
  124.           MOV     CLSTSEC,AX                    ;   and Save
  125.           MOV     CX,FATBUF[14]                 ; Read # of Reserved Sectors
  126.           MOV     AL,BYTE PTR FATBUF[16]        ; Read # of FAT's
  127.           XOR     AH,AH                         ; Convert to Word
  128.           MOV     BX,FATBUF[22]                 ; Read Sectors per FAT
  129.           MOV     FATSEC,BX
  130.           MUL     BX                            ; Calculate Total FAT Sectors
  131.           ADD     CX,AX                         ; Add to Reserved Sectors
  132.           MOV     AX,FATBUF[17]                 ; Read Number of DIR Entries
  133.           MOV     RDIR_LEN,AX
  134.           PUSH    CX                            ; Calculate DIR Sectors
  135.           MOV     CL,5
  136.           SHL     AX,CL
  137.           POP     CX
  138.           MOV     BX,SECSIZE
  139.           XOR     DX,DX
  140.           DIV     BX
  141.           OR      DX,DX                         ; Adjust for Partial Sector
  142.           JZ      NO_ADD
  143.           INC     AX
  144. NO_ADD:   MOV     DIRSEC,AX                     ; Save DIR Sectors
  145.           ADD     CX,AX                         ; Add DIR Sectors to Reserved
  146.           MOV     STARTSEC,CX                   ; Save in STARTSEC
  147.           MOV     AX,FATSEC                     ; Determine FAT Buffer Size
  148.           MOV     BX,SECSIZE
  149.           MUL     BX
  150.           ADD     AX,OFFSET FATBUF
  151.           MOV     DIRBUF,AX                     ; Save DIRBUF Pointer
  152.           MOV     AX,FATBUF[19]                 ; Read Total Sectors on Media
  153.           SUB     AX,CX                         ; Calculate Total Data Clusters
  154.           MOV     BX,CLSTSEC
  155.           XOR     DX,DX
  156.           DIV     BX
  157.           ADD     AX,2
  158.           MOV     CLSTTOT,AX                    ;   and Save
  159.           CMP     AX,4081                       ; If Necessary, Adjust FAT Size
  160.           JLE     FAT_OK
  161.           MOV     FATSIZE,4
  162.           MOV     EOF,0FFF8H
  163. FAT_OK:   MOV     AL,DRIVE                      ; Read FAT
  164.           MOV     CX,FATSEC
  165.           MOV     DX,1
  166.           MOV     BX,OFFSET FATBUF
  167.           INT     25H
  168.           JC      RDERROR                       ; If Error, Say So
  169.           POPF
  170.           MOV     BX,CLUST                      ; Get Cluster Number
  171.           MOV     AX,BX                         ; Convert Cluster # to Decimal
  172.           MOV     DI,OFFSET CLUSTMSG[13]
  173.           CALL    DEC5OUT
  174.           CALL    STRIP0                        ; Strip Off Leading Zeroes
  175.           MOV     AH,9
  176.           MOV     DX,OFFSET CLUSTMSG            ; Output Cluster Message
  177.           INT     21H
  178.           CMP     BX,CLSTTOT                    ; Test Cluster Number
  179.           JNB     CLSTBAD
  180.           CMP     BX,2
  181.           JNB     CLST_OK
  182. CLSTBAD:  MOV     DX,OFFSET INVALID             ; If Invalid, Say So
  183.           JMP     SHORT ERROUT
  184. CLST_OK:  CALL    NEXTCLST                      ; Determine Next Cluster
  185.           OR      BX,BX                         ; If Not in Use, Say So
  186.           JNZ     NOT_FREE
  187.           MOV     DX,OFFSET FREEMSG
  188.           JMP     SHORT ERROUT
  189. NOT_FREE: MOV     AX,EOF                        ; If In Use, Continue
  190.           CMP     BX,AX
  191.           JAE     CLSTGOOD
  192.           DEC     AX                            ; If Bad, Say So
  193.           CMP     BX,AX
  194.           JNE     NOT_BAD
  195.           MOV     DX,OFFSET BADMSG
  196.           JMP     SHORT ERROUT
  197. NOT_BAD:  SUB     AX,7                          ; If Reserved, Say So
  198.           CMP     BX,AX
  199.           JB      CLSTGOOD
  200.           MOV     DX,OFFSET RESVMSG
  201. ERROUT:   MOV     AH,9                          ; Output Error Message
  202.           INT     21H
  203.           MOV     AX,4C01H                      ; Exit to DOS
  204.           INT     21H
  205. RDERROR:  POPF                                  ; Handle Read Error
  206.           MOV     AL,DRIVE
  207.           ADD     AL,'A'
  208.           MOV     READERR[20],AL
  209.           MOV     DX,OFFSET READERR
  210.           JMP     SHORT ERROUT
  211. CLSTGOOD: MOV     AX,CLUST                      ; Get Cluster Number
  212. CLSTBACK: MOV     BX,AX                         ; Get Previous Cluster in Chain
  213.           CALL    PREVCLST
  214.           OR      AX,AX                         ; If Not First, Repeat
  215.           JNZ     CLSTBACK
  216.           MOV     CLUST,BX                      ; Save First Cluster in Chain
  217. LOOKHERE: CALL    GETDIR                        ; Load the Current Directory
  218.           CALL    SRCHCLST                      ; Search Directory for Cluster
  219.           JNC     FOUND                         ; If Found, Exit Search Loop
  220.           CALL    SRCHDIR                       ; Search Dir for Sub-Directory
  221.           JNC     LOOKHERE                      ; If Found, Continue Search Loop
  222.           CALL    DIRNEXT                       ; Use Next Sub-Directory
  223.           JNC     LOOKHERE                      ; If Found, Continue Search Loop
  224.           MOV     DX,OFFSET LOSTMSG             ; Else Couldn't find Cluster
  225.           JMP     ERROUT
  226. FOUND:    MOV     AL,DRIVE                      ; Convert Drive Number to Letter
  227.           ADD     AL,'A'
  228.           MOV     FILESPEC,AL
  229.           MOV     AH,9                          ; Output Owner Message
  230.           MOV     DX,OFFSET OWNERMSG
  231.           INT     21H
  232.           MOV     DX,OFFSET FILESPEC            ; Output FileSpec
  233.           INT     21H
  234.           MOV     DX,OFFSET FILENAME            ; Output FileName
  235.           INT     21H
  236.           MOV     DX,OFFSET CRLF
  237.           INT     21H
  238. EXIT:     MOV     AX,4C00H                      ; Exit to DOS
  239.           INT     21H
  240.  
  241. DIRNEXT:  PUSH    AX                            ; Save Registers
  242.           PUSH    BX
  243.           PUSH    CX
  244.           PUSH    DI
  245.           PUSH    SI
  246. DIRNEXT1: MOV     DI,OFFSET PATH                ; Scan to End of Path
  247.           MOV     CX,80
  248.           MOV     AL,'$'
  249.           REPNE   SCASB
  250.           JNE     DIRNEXT3                      ; If No End, Error
  251.           CMP     CX,79                         ; If Null Path, Error
  252.           JE      DIRNEXT3
  253.           STD                                   ; Auto-Decrement
  254.           MOV     AX,78                         ; Determine Path Length
  255.           SUB     AX,CX
  256.           MOV     CX,AX
  257.           SUB     DI,2                          ; Point to End of DirName
  258.           MOV     AL,0                          ; Set End of DirName
  259.           STOSB
  260.           MOV     AL,'\'                        ; Scan to Previous DirName
  261.           REPNE   SCASB
  262.           JE      DIRNEXT2                      ; If Not Found,
  263.           MOV     DI,OFFSET PATH[-2]            ;   Point to Start of Path
  264. DIRNEXT2: CLD                                   ; Auto-Increment
  265.           ADD     DI,2                          ; Copy Last SubDir to FileName
  266.           PUSH    DI
  267.           MOV     SI,DI
  268.           MOV     DI,OFFSET FILENAME
  269.           CALL    MOVSTR
  270.           POP     DI
  271.           MOV     AL,'$'                        ; Terminate Path String
  272.           STOSB
  273.           CALL    GETDIR                        ; Read Directory
  274.           JC      DIRNEXT4                      ; If Error, Say So
  275.           MOV     SI,OFFSET FILENAME
  276.           MOV     DI,OFFSET DIRNAME
  277.           CALL    MOVSTR
  278.           CALL    SRCHFILE                      ; Search for FileName
  279.           JC      DIRNEXT4                      ; If Error, Say So
  280.           MOV     SI,BX                         ; Save Pointer
  281.           ADD     SI,32                         ; Point to Next Dir Entry
  282.           MOV     AX,SI                         ; Determine Dir Entry Count
  283.           SUB     AX,DIRBUF
  284.           MOV     CL,5
  285.           SHR     AX,CL
  286.           MOV     CX,DIR_LEN
  287.           SUB     CX,AX
  288.           CALL    FINDDIR                       ; Find Next SubDirectory
  289.           JC      DIRNEXT1
  290.           JMP     SHORT DIRNEXT4
  291. DIRNEXT3: STC                                   ; Set Error Return Flag
  292. DIRNEXT4: POP     SI                            ; Restore Registers
  293.           POP     DI
  294.           POP     CX
  295.           POP     BX
  296.           POP     AX
  297.           RET                                   ; Done
  298.  
  299. GETDIR:   PUSH    AX                            ; Save Registers
  300.           PUSH    BX
  301.           PUSH    CX
  302.           PUSH    DX
  303.           PUSH    DI
  304.           PUSH    SI
  305.           MOV     AL,DRIVE                      ; Read Root Directory
  306.           MOV     CX,DIRSEC
  307.           MOV     DX,STARTSEC
  308.           SUB     DX,CX
  309.           MOV     BX,DIRBUF
  310.           INT     25H
  311.           POPF
  312.           MOV     AX,RDIR_LEN                   ; DIR Length = Root DIR Length
  313.           MOV     DIR_LEN,AX
  314.           MOV     SI,OFFSET PATH                ; Point to First Element of Path
  315. GETDIR1:  MOV     DI,OFFSET DIRNAME             ; Point to FileName Buffer
  316. GETDIR2:  LODSB                                 ; Copy Path Element to FileName
  317.           CMP     AL,'\'                        ;   until '\' or '$'
  318.           JE      GETDIR3
  319.           CMP     AL,'$'
  320.           JE      GETDIR4
  321.           STOSB
  322.           JMP     SHORT GETDIR2
  323. GETDIR3:  MOV     AL,0                          ; Read Subdirectory
  324.           STOSB
  325.           CALL    READDIR
  326.           JC      GETDIR5                       ; If Error, Say So
  327.           JMP     SHORT GETDIR1                 ; Get Next Element
  328. GETDIR4:  CLC                                   ; Clear Error Flag
  329. GETDIR5:  POP     SI                            ; Restore Registers
  330.           POP     DI
  331.           POP     DX
  332.           POP     CX
  333.           POP     BX
  334.           POP     AX
  335.           RET                                   ; Done
  336.  
  337. READDIR:  PUSH    CX                            ; Save Registers
  338.           PUSH    DI
  339.           PUSH    SI
  340.           CALL    SRCHFILE                      ; Search for DIR
  341.           JC      READDIR2                      ; If Not Found, Error
  342.           MOV     BX,[BX+26]                    ; Get Starting Cluster Number
  343.           MOV     DIR_LEN,0                     ; DIR Length = 0
  344.           OR      BX,BX                         ; If Start Cluster = 0, Error
  345.           JZ      READDIR2
  346.           MOV     AX,SECSIZE                    ; Calculate DIR Entries/Cluster
  347.           MOV     CX,CLSTSEC
  348.           MUL     CX
  349.           MOV     CL,5
  350.           SHR     AX,CL
  351.           MOV     CX,AX
  352.           MOV     DI,DIRBUF                     ; Point to DIR Buffer
  353. READDIR1: CALL    READCLST                      ; Read Cluster
  354.           ADD     DIR_LEN,CX                    ; Increment DIR Length
  355.           CMP     BX,EOF                        ; If Not Last Cluster,
  356.           JB      READDIR1                      ;   Get Next Cluster
  357.           JMP     SHORT READDIR3                ; Done Reading DIR
  358. READDIR2: STC                                   ; Set Error Flag
  359. READDIR3: POP     SI                            ; Restore Registers
  360.           POP     DI
  361.           POP     CX
  362.           RET                                   ; Done
  363.  
  364. SRCHDIR:  PUSH    CX                            ; Save Registers
  365.           PUSH    SI
  366.           MOV     SI,DIRBUF                     ; Point to First DIR Entry
  367.           MOV     CX,DIR_LEN                    ; Load DIR Length
  368.           CALL    FINDDIR                       ; Find SubDirectory
  369.           POP     SI                            ; Restore Registers
  370.           POP     CX
  371.           RET                                   ; Done
  372.  
  373. FINDDIR:  PUSH    AX                            ; Save Registers
  374.           PUSH    DI
  375. FINDDIR1: JCXZ    FINDDIR4                      ; If Zero, Not Found
  376. FINDDIR2: CMP     BYTE PTR [SI],'.'             ; If '.' or '..', Skip
  377.           JE      FINDDIR3
  378.           CMP     BYTE PTR [SI],0E5H            ; If Deleted, Skip
  379.           JE      FINDDIR3
  380.           TEST    BYTE PTR [SI+11],10H          ; Test File Attribute
  381.           JNZ     FINDDIR5                      ; If Match, Found
  382. FINDDIR3: ADD     SI,32                         ; Else Next DIR Entry
  383.           LOOP    FINDDIR2                      ; and Repeat
  384. FINDDIR4: STC                                   ; Set Error Flag
  385.           JMP     SHORT FINDDIR6                ; Done
  386. FINDDIR5: MOV     DI,OFFSET DIRNAME
  387.           CALL    UNPARSE                       ; UnParse Directory Name
  388.           MOV     DI,OFFSET PATH                ; Search for End of Path
  389.           MOV     AL,'$'
  390.           MOV     CX,80
  391.           REPNE   SCASB
  392.           JNE     FINDDIR4                      ; If Not Found, Error
  393.           DEC     DI
  394.           MOV     BX,SI                         ; Set Pointer to DIR Entry
  395.           MOV     SI,OFFSET DIRNAME             ; Copy Directory Name to Path
  396.           CALL    MOVSTR
  397.           DEC     DI
  398.           MOV     AX,'$\'                       ; Terminate Path
  399.           STOSW
  400.           CLC                                   ; Clear Error Flag
  401. FINDDIR6: POP     DI                            ; Restore Registers
  402.           POP     AX
  403.           RET                                   ; Done
  404.  
  405. SRCHFILE: PUSH    AX                            ; Save Register
  406.           PUSH    CX
  407.           PUSH    DI
  408.           PUSH    SI
  409.           MOV     AX,2900H                      ; Parse Filename
  410.           MOV     SI,OFFSET DIRNAME
  411.           MOV     DI,OFFSET FCB
  412.           INT     21H
  413.           INC     DI                            ; Point to Filename in FCB
  414.           MOV     SI,DIRBUF                     ; Point to Start of DIRBUF
  415.           MOV     CX,DIR_LEN                    ; Load DIR Length
  416.           JCXZ    SRCHFIL2                      ; If Zero, Not Found
  417. SRCHFIL1: PUSH    CX                            ; Save Registers
  418.           PUSH    DI
  419.           PUSH    SI
  420.           MOV     CX,11                         ; Compare Filename
  421.           REPE    CMPSB
  422.           POP     SI                            ; Restore Registers
  423.           POP     DI
  424.           POP     CX
  425.           JE      SRCHFIL3                      ; If Match, Found
  426.           ADD     SI,32                         ; Else Next DIR Entry
  427.           LOOP    SRCHFIL1                      ; and Repeat
  428. SRCHFIL2: STC                                   ; Set Error Flag
  429.           JMP     SHORT SRCHFIL4                ; Done
  430. SRCHFIL3: MOV     BX,SI                         ; Set Pointer to DIR Entry
  431.           CLC                                   ; Clear Error Flag
  432. SRCHFIL4: POP     SI                            ; Restore Registers
  433.           POP     DI
  434.           POP     CX
  435.           POP     AX
  436.           RET                                   ; Done
  437.  
  438. SRCHCLST: PUSH    AX                            ; Save Register
  439.           PUSH    CX
  440.           PUSH    DI
  441.           PUSH    SI
  442.           MOV     SI,DIRBUF                     ; Point to First DIR Entry
  443.           MOV     CX,DIR_LEN                    ; Load DIR Length
  444.           JCXZ    SRCHCLS3                      ; If Zero, Not Found
  445.           MOV     BX,CLUST
  446. SRCHCLS1: CMP     BYTE PTR [SI],'.'             ; If '.' or '..', Skip
  447.           JE      SRCHCLS2
  448.           CMP     BYTE PTR [SI],0E5H            ; If Deleted, Skip
  449.           JE      SRCHCLS2
  450.           CMP     BX,[SI+26]                    ; Compare Start Cluster Number
  451.           JE      SRCHCLS4                      ; If Match, Found
  452. SRCHCLS2: ADD     SI,32                         ; Else Next DIR Entry
  453.           LOOP    SRCHCLS1                      ; and Repeat
  454. SRCHCLS3: STC                                   ; Set Error Flag
  455.           JMP     SHORT SRCHCLS5                ; Done
  456. SRCHCLS4: MOV     DI,OFFSET FILENAME            ; UnParse File Name
  457.           CALL    UNPARSE
  458.           CLC                                   ; Clear Error Flag
  459. SRCHCLS5: POP     SI                            ; Restore Registers
  460.           POP     DI
  461.           POP     CX
  462.           POP     AX
  463.           RET                                   ; Done
  464.  
  465. READCLST: PUSH    AX                            ; Save Registers
  466.           PUSH    CX
  467.           PUSH    DX
  468.           MOV     AX,BX                         ; Calculate Absolute Sector #
  469.           SUB     AX,2
  470.           MOV     CX,CLSTSEC
  471.           MUL     CX
  472.           ADD     AX,STARTSEC
  473.           MOV     DX,AX
  474.           MOV     AL,DRIVE
  475.           PUSH    BX                            ; Save Registers
  476.           PUSH    DI
  477.           MOV     BX,DI                         ; Read Cluster
  478.           INT     25H
  479.           POPF
  480.           POP     DI                            ; Restore Registers
  481.           POP     BX
  482.           CALL    NEXTCLST                      ; Get Next Cluster Number
  483.           MOV     AX,CLSTSEC                    ; Increment Buffer Pointer
  484.           MOV     CX,SECSIZE
  485.           MUL     CX
  486.           ADD     DI,AX
  487.           POP     DX                            ; Restore Registers
  488.           POP     CX
  489.           POP     AX
  490.           RET                                   ; Done
  491.  
  492. PREVCLST: PUSH    BX                            ; Save Registers
  493.           PUSH    CX
  494.           PUSH    DX
  495.           MOV     DX,BX                         ; Reserve Cluster Number
  496.           MOV     CX,CLSTTOT                    ; Start Looking at Last Cluster
  497. PREVCLS1: MOV     BX,CX                         ; Check Cluster
  498.           INC     BX
  499.           CALL    NEXTCLST
  500.           CMP     BX,DX                         ; If Match, Use It
  501.           LOOPNE  PREVCLS1                      ; Else Repeat
  502.           JNE     PREVCLS2                      ; If No Match, Return Zero
  503.           ADD     CX,2                          ; Adjust for Cluster Number
  504. PREVCLS2: MOV     AX,CX                         ; AX = Cluster Number
  505.           POP     DX                            ; Restore Registers
  506.           POP     CX
  507.           POP     BX
  508.           RET                                   ; Done
  509.  
  510. NEXTCLST: CMP     FATSIZE,3                     ; If FAT Size = 16 Bits,
  511.           JE      NEXTCLS1
  512.           SHL     BX,1                          ;   Simply Read Next Cluster #
  513.           MOV     BX,FATBUF[BX]
  514.           RET                                   ;   Done
  515. NEXTCLS1: PUSH    AX                            ; Save Registers
  516.           PUSH    CX
  517.           MOV     AX,BX                         ; Word # = Cluster # * 1.5
  518.           SHL     AX,1
  519.           ADD     BX,AX
  520.           SHR     BX,1
  521.           MOV     BX,FATBUF[BX]
  522.           JNC     NEXTCLS2                      ; If Odd, Use 12 MSB's
  523.           MOV     CL,4
  524.           SHR     BX,CL
  525. NEXTCLS2: AND     BX,0FFFH                      ; Else Use 12 LSB's
  526.           POP     CX                            ; Restore Registers
  527.           POP     AX
  528.           RET                                   ; Done
  529.  
  530. UNPARSE:  PUSH    CX                            ; Save Registers
  531.           PUSH    DI
  532.           PUSH    SI
  533.           MOV     CX,8                          ; FileName Length = 8 Max
  534. UNPARSE1: LODSB                                 ; Read Character
  535.           CMP     AL,' '                        ; If Space, Exit Loop
  536.           JE      UNPARSE2
  537.           STOSB                                 ; Move Character
  538.           LOOP    UNPARSE1                      ; Repeat
  539. UNPARSE2: MOV     AL,'.'                        ; Put a Dot in the String
  540.           STOSB
  541.           POP     SI                            ; Point to Extension
  542.           PUSH    SI
  543.           ADD     SI,8
  544.           MOV     CX,3                          ; Extension Length = 3 Max
  545. UNPARSE3: LODSB                                 ; Read Character
  546.           CMP     AL,' '                        ; If Space, Exit Loop
  547.           JE      UNPARSE4
  548.           STOSB                                 ; Move Character
  549.           LOOP    UNPARSE3                      ; Repeat
  550. UNPARSE4: CMP     CX,3                          ; If No Extension, Remove Dot
  551.           JNE     UNPARSE5
  552.           DEC     DI
  553. UNPARSE5: MOV     AL,0                          ; Terminate FileName
  554.           STOSB
  555.           MOV     AL,'$'
  556.           STOSB
  557.           POP     SI                            ; Restore Registers
  558.           POP     DI
  559.           POP     CX
  560.           RET                                   ; Done
  561.  
  562. MOVSTR:   LODSB                                 ; Read Source
  563.           STOSB                                 ; Write Destination
  564.           OR      AL,AL                         ; If Not EOS, Repeat
  565.           JNZ     MOVSTR
  566.           RET                                   ; Done
  567.  
  568. GET_WORD: PUSH    BX                            ; Save Registers
  569.           PUSH    DI
  570.           PUSH    SI                            ; Save Pointer
  571.           XOR     DX,DX                         ; Value = 0
  572. GET_WRD1: LODSB                                 ; Read Character
  573.           CMP     AL,'0'                        ; If Not Numeric, Done
  574.           JB      GET_WRD2
  575.           CMP     AL,'9'
  576.           JA      GET_WRD2
  577.           SUB     AL,'0'                        ; Convert to BCD
  578.           CBW
  579.           MOV     BX,AX                         ; Value = Value*10+BCD
  580.           MOV     AX,10
  581.           MUL     DX
  582.           ADD     AX,BX
  583.           MOV     DX,AX
  584.           JMP     GET_WRD1                      ; Repeat
  585. GET_WRD2: DEC     SI
  586.           POP     DI                            ; Restore Pointer
  587.           CMP     DI,SI                         ; Compare Pointer
  588.           POP     DI                            ; Restore Registers
  589.           POP     BX
  590.           RET                                   ; Done
  591.  
  592. STRIP0:   CMP     BYTE PTR [DI],'0'             ; If Character != '0', Done
  593.           JNE     STRIP1
  594.           CMP     BYTE PTR [DI+1],'0'           ; If Next Character != Digit,
  595.           JL      STRIP1                        ;   Done
  596.           CMP     BYTE PTR [DI+1],'9'
  597.           JG      STRIP1
  598.           MOV     BYTE PTR [DI],' '             ; Change '0' to ' '
  599.           INC     DI                            ; Point to Next Character
  600.           JMP     SHORT STRIP0                  ; Repeat
  601. STRIP1:   RET                                   ; Done
  602.  
  603. DEC2OUT:  PUSH    AX                            ; Save Registers
  604.           PUSH    BX
  605.           XOR     AH,AH                         ; Clear AH
  606.           MOV     BL,10                         ; AH=AX%10,AL=AX/10
  607.           DIV     BL
  608.           ADD     AX,'00'                       ; Convert to ASCII
  609.           SUB     DI,2
  610.           MOV     [DI],AX                       ; Store in String
  611.           POP     BX                            ; Restore Registers
  612.           POP     AX
  613.           RET                                   ; Done
  614.  
  615. DEC4OUT:  PUSH    AX                            ; Save Registers
  616.           PUSH    BX
  617.           MOV     BL,100                        ; AH=AX%100,AL=AX/100
  618.           DIV     BL
  619.           XCHG    AH,AL                         ; Convert 2 LSD's
  620.           CALL    DEC2OUT
  621.           XCHG    AH,AL                         ; Convert 2 MSD's
  622.           CALL    DEC2OUT
  623.           POP     BX                            ; Restore Registers
  624.           POP     AX
  625.           RET                                   ; Done
  626.  
  627. DEC5OUT:  PUSH    AX                            ; Save Registers
  628.           PUSH    BX
  629.           PUSH    DX                            ; DX=AX%10000,AX=AX/10000
  630.           MOV     BX,10000
  631.           XOR     DX,DX
  632.           DIV     BX
  633.           XCHG    DX,AX                         ; Convert 4 LSD's
  634.           CALL    DEC4OUT
  635.           XCHG    DX,AX                         ; Convert MSD
  636.           ADD     AL,'0'
  637.           SUB     DI,1
  638.           MOV     [DI],AL
  639.           POP     DX                            ; Restore Registers
  640.           POP     BX
  641.           POP     AX
  642.           RET                                   ; Done
  643.  
  644. FATBUF    LABEL   WORD
  645.  
  646. CODE      ENDS
  647.  
  648.           END     OWNER
  649.