home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / fileutil / ddir5.arj / DDIR5.ASM next >
Encoding:
Assembly Source File  |  1991-12-13  |  13.9 KB  |  475 lines

  1. ;    DDIR.ASM -- Double Column Sorted DIR Command
  2. ;    ========
  3. ;            (C) Copyright Charles Petzold, 1985
  4. ;
  5. ;                       Modified 4/3/89 by Harron K. Appleman for DOS 4.0
  6. ;            Modified 12/13/91 by Joseph "Skip" Reymann for
  7. ;              to sense screen line count and fill screen,
  8. ;              whatever the size.
  9. ;
  10. ;            COM file format
  11. ;
  12.     
  13. CSEG        Segment
  14.  
  15.         Assume    CS:CSEG, DS:CSEG
  16.  
  17.         Org    002Ch            ; Offset of Environment
  18. Environment    Label    Word
  19.  
  20.         Org    007Bh            ; Parameter for COMMAND.COM
  21. NewParameter    Label    Byte
  22.  
  23.         Org    0080h            ; Parameter passed to program
  24. OldParameter    Label    Byte    
  25.  
  26.         Org    0100h            ; Entry point
  27. Entry:        Jmp    Begin
  28.  
  29. ;    All Data
  30. ;    --------
  31.  
  32.         db    '(C) Copyright Charles Petzold, 1985'
  33.  
  34. DosVersMsg    db    "Needs DOS 2.0 +$"    ; Error messages
  35. MemAllocMsg    db    "Memory Problem$"
  36. CommandMsg    db    "COMMAND Problem$"
  37.  
  38. Comspec        db    "COMSPEC="        ; Search string in environment
  39. CommandAsciiz    dd    ?            ; Eventual pointer to COMMAND 
  40.  
  41. ParamBlock    dw    ?            ; Parameter Block for EXEC
  42.         dw    NewParameter,?        ; First ? must be replaced
  43.         dw    5Ch,?            ;    with Environment segment;
  44.         dw    6Ch,?            ;    others with this segment
  45.  
  46. OldInterrupt21    dd    ?            ; For vector address storage
  47.  
  48. BufferPtr    dw    Offset FileBuffer    ; For storing files listing
  49. CharCounter    dw    0            ; Keeps track of characters
  50. NowDoingFile    db    0            ; Flagged for file printed
  51. WithinFileList    db    0            ; Flagged for file list
  52. FileCounter    dw    0            ; Keeps track of files
  53. LineCounter    db    0            ; For pausing at screen end
  54. LinesPerScreen    dw    0            ; Holds calculated lines-per-screen
  55.  
  56. PauseMessage    db    6 dup (205)," Press any key to continue "
  57.         db    6 dup (205),181 
  58. PauseMsgEnd    Label    Byte
  59.  
  60. ;    Check DOS Version
  61. ;    -----------------
  62.  
  63. Begin:        Mov    AH,30h            ; DOS Version function call
  64.         Int    21h            ; Call DOS
  65.         Cmp    AL,2            ; Check if version 2 
  66.         Jae    DosVersOK        ; If equal or over, all OK
  67.  
  68.         Mov    DX,Offset DosVersMsg    ; Wrong DOS version message
  69. ErrorExit:    Mov    AH,9            ; Set up for string write
  70.         Int    21h            ; Call DOS for message
  71.  
  72.         Int    20h            ; Dishonorable discharge
  73.  
  74. ;    Adjust stack and un-allocate rest of memory 
  75. ;    -------------------------------------------
  76.  
  77. DosVersOK:    Mov    DI,Offset FileBuffer    ; Place to save files
  78.         Mov    CX,528 * 39        ; Allow room for 528 files
  79.         Mov    AL,' '            ; Will clear with blanks
  80.         Cld                ; Forward direction
  81.         Rep    Stosb            ; Clear the area
  82.  
  83.         Mov     BX,(Offset FileBuffer) + (528 * 39) + 100h
  84.                          ; New end of program
  85.         Mov    SP,BX            ; Set the stack pointer
  86.         Add    BX,15            ; Add 15 for rounding
  87.         Mov    CL,4            ; Number of shifts
  88.         Shr    BX,CL            ; Convert AX to segment
  89.  
  90.         Mov    AH,4Ah            ; DOS call to shrink down
  91.         Int    21h            ;    allocated memory
  92.  
  93.         Mov    DX,Offset MemAllocMsg    ; Possible error message
  94.         Jc    ErrorExit        ; Only print it if Carry set
  95.  
  96. ;    Compute Number of lines per screen
  97. ;    ---------------------------------
  98.  
  99.         Push    ES            ; Save register
  100.         Push    AX
  101.         Push    DX
  102.         Push    DI
  103.         Mov    AX,40H            ; Point to ROM comm area
  104.         Mov    ES,AX            ; And save it
  105.         Mov    DI,4CH            ; And screen size in bytes
  106.         Mov    AX,ES:[DI]        ; Get screen size in bytes
  107.         Shr    AX,1            ; Change bytes->words
  108.         Sub    DX,DX            ; Clear high word
  109.         Mov    DI,4AH            ; And screen size in bytes
  110.         Div    Word Ptr ES:[DI]    ; Compute lines per screen
  111.         Dec    AX            ; Reserve one line
  112.         Mov    LinesPerScreen,AX    ; Save linecount
  113.         Pop    DI            ; Restore register
  114.         Pop    DX            ; Restore register
  115.         Pop    AX            ; Restore register
  116.         Pop    ES            ; Restore register
  117.  
  118. ;    Search for Comspec in Environment
  119. ;    ---------------------------------
  120.  
  121.         Mov    ES,[Environment]    ; Environment Segment
  122.         Sub    DI,DI            ; Start search at beginning
  123.         Cld                ; String increment to forward
  124.  
  125. TryThis:    Cmp    Byte Ptr ES:[DI],0    ; See if end of environment
  126.         Jz    NoFindComSpec        ; If so, we have failed
  127.         
  128.         Push    DI            ; Save environment pointer
  129.         Mov    SI,Offset ComSpec    ; String to search for
  130.         Mov    CX,8            ; Characters in search string
  131.         Repz    Cmpsb            ; Check if strings are same
  132.         Pop    DI            ; Get back the pointer
  133.  
  134.         Jz    FoundComspec        ; Found string only zero flag
  135.  
  136.         Sub    AL,AL            ; Zero out AL
  137.         Mov    CX,8000h        ; Set for big search
  138.         Repnz    Scasb            ; Find the next zero in string
  139.         Jmp    TryThis            ; And do the search from there
  140.  
  141. NoFindComSpec:    Mov    DX,Offset CommandMsg    ; Message for COMSPEC error
  142.         Jmp    ErrorExit        ; Print it and exit
  143.  
  144. FoundComspec:    Add    DI,8            ; So points after 'COMSPEC='
  145.         Mov    Word Ptr [CommandASCIIZ],DI    ; Save the address of
  146.         Mov    Word Ptr [CommandASCIIZ + 2],ES    ;    COMMAND ASCIIZ
  147.  
  148. ;     Set up parameter block for EXEC call
  149. ;    ------------------------------------
  150.  
  151.         Mov    [ParamBlock],ES        ; Segment of Environment string
  152.         Mov    [ParamBlock + 4],CS    ; Segment of this program
  153.         Mov    [ParamBlock + 8],CS    ;    so points to FCB's
  154.         Mov    [ParamBlock + 12],CS    ;    and NewParameter
  155.  
  156. ;    Save and set Interrupt 21h vector address
  157. ;    ----------------------------------------- 
  158.  
  159.         Mov    AX,3521h        ; DOS call to get Interrupt 21
  160.         Int    21h            ;    vector address
  161.         Mov    Word Ptr [OldInterrupt21],BX        ; Save offset
  162.         Mov    Word Ptr [OldInterrupt21 + 2],ES    ; And segment    
  163.  
  164.         Mov    DX,Offset NewInterrupt21; Address of new Interrupt 21 
  165.         Mov    AX,2521h        ; Do DOS call to
  166.         Int    21h            ;    set the new address
  167.  
  168. ;    Fix up new parameter for "/C DIR" String
  169. ;    ------------------------------------
  170.  
  171.         Mov    AL,[OldParameter]    ; Number of parameter chars     
  172.         Add    AL,5            ; We'll be adding five more
  173.         Mov    [NewParameter],AL    ; Save it
  174.         Mov    Word Ptr [NewParameter + 1],'C/'    ; i.e. "/C"
  175.         Mov    Word Ptr [NewParameter + 3],'ID'    ; Then "DI"    
  176.         Mov    Byte Ptr [NewParameter + 5],'R'        ; And "R"
  177.  
  178. ;     Load COMMAND.COM
  179. ;     -----------------
  180.         
  181.         Push    CS            ; Push this segment so we can
  182.         Pop    ES            ;    set ES to it
  183.         Mov    BX,Offset ParamBlock    ; ES:BX = address of block
  184.         Lds    DX,[CommandAsciiz]    ; DS:DX = address of ASCIIZ
  185.         Mov    AX,4B00h        ; EXEC call 4Bh, type 0
  186.         Int    21h            ; Load command processor
  187.  
  188. ;     Return from COMMAND.COM
  189. ;    -----------------------
  190.  
  191.         Mov    AX,CS        ; Get this segment in AX
  192.         Mov    DS,AX        ; Set DS to it
  193.         Mov    SS,AX        ; And SS for stack segment
  194.         Mov    SP,(Offset FileBuffer) + (528 * 39) + 100h
  195.                     ; Set Stack again
  196.  
  197.         PushF            ; Save Carry for error check 
  198.         Push    DS        ; Save DS during next call
  199.  
  200.         Mov    DX,Word Ptr [OldInterrupt21]    ; Old Int 21 offset
  201.         Mov    DS,Word Ptr [OldInterrupt21 + 2]; and segment
  202.         Mov    AX,2521h        ; Call DOS to set vector
  203.         Int    21h            ;    address to original    
  204.  
  205.         Pop    DS            ; Restore DS to this segment
  206.         PopF                ; Get back Carry flage
  207.  
  208.         Jnc    NormalEnd        ; Continue if no error
  209.  
  210.         Mov    DX,Offset CommandMsg    ; Otherwise we'll print error
  211.         Jmp    ErrorExit        ;    message and exit
  212.  
  213. NormalEnd:    Int    20h            ; Terminate program
  214.  
  215. ;    New Interrupt 21h
  216. ;    -----------------
  217.  
  218. NewInterrupt21    Proc    Far
  219.  
  220.         Sti                ; Allow further interrupts
  221.         Cmp    AH,40h            ; Check if file / device write
  222.         Je    CheckHandle        ; If so, continue checks
  223.  
  224. SkipIntercept:    Jmp    CS:[OldInterrupt21]    ; Just jump to old interrupt
  225.  
  226. CheckHandle:    Cmp    BX,1            ; Check if standard output
  227.         Jne    SkipIntercept        ; Not interested if not
  228.  
  229.         PushF                ; Push all registers that
  230.         Push    AX            ;    we'll be messing with
  231.         Push    CX
  232.         Push    SI
  233.         Push    DI
  234.         Push    ES
  235.  
  236.         Push    CS            ; Push the code segment
  237.         Pop    ES            ; So we can set ES to it
  238.         Cld                ; Forward for string transfers
  239.         Mov    SI,DX            ; Now DS:SI = text source
  240.         Mov    DI,CS:[BufferPtr]    ; And ES:DI = text destination
  241.  
  242.         Cmp    CX,2            ; See if two chars to write
  243.         Jne    RegularChars        ; If not, can't be CR/LF
  244.  
  245.         Cmp    Word Ptr DS:[SI],0A0Dh    ; See if CR/LF being written
  246.         Jne    RegularChars        ; Skip rest if not CR/LF
  247.  
  248.         Mov    CX,CS:[CharCounter]    ; Get characters in line
  249.         Mov    CS:[CharCounter],0    ; Start at new line
  250.         Cmp    CS:[NowDoingFile],1    ; See if CR/LF terminates file
  251.         Jnz    AllowTransfer        ; If not, just write to screen
  252.  
  253.         Mov    AX,39            ; Max characters per line
  254.         Sub    AX,CX            ; Subtract those passed 
  255.         Add    CS:[BufferPtr],AX    ; Kick up pointer by that
  256.         Mov    CS:[NowDoingFile],0    ; Finished with file
  257.         Jmp    PopAndReturn        ; So just return to COMMAND
  258.  
  259. RegularChars:    Add    CS:[CharCounter],CX    ; Kick up counter by number
  260.         Cmp    CS:[CharCounter],CX    ; See if beginning of line
  261.         Jne    NotLineBegin        ; If not, must be in middle
  262.  
  263.         Cmp    Byte Ptr DS:[SI],' '    ; See if first char is blank
  264.         Jne    CheckForFile        ; If not, check 2nd char
  265.  
  266. Resume:        Cmp    CS:[WithinFileList],1    ; See if doing file listing
  267.         Jne    AllowTransfer        ; If not, just print stuff
  268.  
  269.         Call    SortAndList        ; Files done -- sort and list
  270.         Mov    CS:[WithinFileList],0    ; Not doing files now
  271.         Jmp    Short AllowTransfer    ; So just print the stuff
  272.  
  273. CheckForFile:    Cmp     Byte Ptr DS:[SI+1],61H  ; See if 2nd char is lower 
  274.                 Jge     Resume                  ; case -- if so, not a file
  275.  
  276. ItsAFile:    Cmp    CS:[FileCounter],528    ; See if 11 buffer filled up
  277.         Jb    NotTooManyFiles        ; If not just continue
  278.  
  279.         Push    CX            ; Otherwise, save this register
  280.         Call    SortAndList        ; Print all up to now
  281.         Mov    CS:[FileCounter],0    ; Reset the counter
  282.         Mov    DI,Offset FileBuffer    ; And the pointer
  283.         Mov    CS:[BufferPtr],DI    ; Save the pointer
  284.         Mov    CX,528 * 39        ; Will clear for 528 files
  285.         Mov    AL,' '            ; With a blank
  286.         Rep    Stosb            ; Clear it out
  287.         Pop    CX            ; And get back register
  288.  
  289. NotTooManyFiles:Mov    CS:[WithinFileList],1    ; We're doing files now
  290.         Mov    CS:[NowDoingFile],1    ; And a file in particular
  291.         Inc    CS:[FileCounter]    ; So kick up this counter
  292.  
  293. NotLineBegin:    Cmp    CS:[NowDoingFile],1    ; See if doing files
  294.         Je    StoreCharacters        ; If so, store the stuff
  295.  
  296. AllowTransfer:    Pop    ES            ; Pop all the registers
  297.         Pop    DI
  298.         Pop    SI
  299.         Pop    CX
  300.         Pop    AX
  301.         PopF
  302.  
  303.         Jmp    SkipIntercept        ; And go to DOS for print
  304.  
  305. StoreCharacters:Mov    DI,CS:[BufferPtr]    ; Set destination
  306.         Rep    Movsb            ; Move characters to buffer
  307.         Mov    CS:[BufferPtr],DI    ; And save new pointer    
  308.  
  309. PopAndReturn:    Pop    ES            ; Pop all the registers
  310.         Pop    DI
  311.         Pop    SI
  312.         Pop    CX
  313.         Pop    AX
  314.         PopF
  315.  
  316.         Mov    AX,CX            ; Set for COMMAND.COM
  317.         Clc                ; No error here 
  318.         Ret    2            ; Return with CY flag cleared
  319.  
  320. NewInterrupt21    EndP
  321.  
  322. ;    Sort Files
  323. ;    ----------
  324.  
  325. SortAndList:    Push    BX            ; Push a bunch of registers
  326.         Push    DX
  327.         Push    SI
  328.         Push    DS
  329.  
  330.         Push    CS            ; Push CS
  331.         Pop    DS            ;    so we can set DS to it
  332.         Assume    DS:CSEG            ; And inform the assembler
  333.  
  334.         Mov    DI,Offset FileBuffer    ; This is the beginning
  335.         Mov    CX,[FileCounter]    ; Number of files to sort
  336.         Dec    CX            ; Loop needs one less than that 
  337.         Jcxz    AllSorted        ; But zero means only one file
  338.  
  339. SortLoop1:    Push    CX            ; Save the file counter
  340.         Mov    SI,DI            ; Set source to destination
  341.  
  342. SortLoop2:    Add    SI,39            ; Set source to next file
  343.  
  344.         Push    CX            ; Save the counter,
  345.         Push    SI            ;    compare source,
  346.         Push    DI            ;    and compare destination
  347.  
  348.         Mov    CX,39            ; 39 characters to compare
  349.         Repz    Cmpsb            ; Do the compare
  350.         Jae    NoSwitch        ; Jump if already in order
  351.  
  352.         Pop    DI            ; Get back these registers
  353.         Pop    SI
  354.  
  355.         Push    SI            ; And push them again for move
  356.         Push    DI
  357.  
  358.         Mov    CX,39            ; 39 characters
  359. SwitchLoop:    Mov    AL,ES:[DI]        ; Character from destination 
  360.         Movsb                ; Source to destination
  361.         Mov    DS:[SI - 1],AL        ; Character to source
  362.         Loop    SwitchLoop        ; For the rest of the line
  363.  
  364. NoSwitch:    Pop    DI            ; Get back the registers
  365.         Pop    SI
  366.         Pop    CX
  367.         Loop    SortLoop2        ; And loop for next file
  368.  
  369.         Pop    CX            ; Get back file counter 
  370.         Add    DI,39            ; Compare with next file
  371.         Loop    SortLoop1        ; And loop again
  372.  
  373. ;    Now Display Sorted Files
  374. ;    ------------------------
  375.  
  376. AllSorted:    Mov    SI,Offset FileBuffer    ; This is the beginning
  377.         Mov    CX,[FileCounter]    ; Number of files to list
  378.         Inc    CX            ; In case CX is odd
  379.         Shr    CX,1            ; CX now is number of lines
  380.  
  381. SetIncrement:    Mov    AX,39            ; Line length
  382.         Mul    [LinesPerScreen]    ; Increment for double list
  383.         Mov    BX,AX
  384.         Cmp    CX,[LinesPerScreen]    ; But use it only if a full
  385.         Jae    LineLoop        ;    screen is printed    
  386.  
  387.         Mov    AX,39            ; Otherwise find increment
  388.         Mul    CX            ;    by multiplying CX by 39
  389.         Mov    BX,AX            ; And make that the increment
  390.  
  391. LineLoop:    Call    PrintFile        ; Print the first column file
  392.         Mov    AL,' '            ; Skip one space
  393.         Call    PrintChar        ;    by printing blank
  394.         Mov    AL,179            ; Put a line down the middle
  395.         Call    PrintChar
  396.         Mov    AL,' '            ; Skip another space
  397.         Call    PrintChar
  398.  
  399.         Add    SI,BX            ; Bump up source by increment
  400.         Sub    SI,39             ; But kick down by 39
  401.  
  402.         Call    PrintFile        ; Print the second column file
  403.         Call    CRLF            ; And terminate line
  404.  
  405.         Sub    SI,BX            ; Bring pointer back down
  406.  
  407.         Inc    [LineCounter]        ; One more line completed
  408.         Mov    AX,[LinesPerScreen]    ; Get line count
  409.         Cmp    [LineCounter],AL    ; Have we done whole screen?
  410.         Jz    PauseAtEnd        ; If so, gotta pause now
  411.  
  412.         Loop    LineLoop        ; Otherwise just loop
  413.         Jmp    Short AllFinished    ; And jump out when done
  414.  
  415. PauseAtEnd:    Mov    [LineCounter],0        ; Reset the counter
  416.         Add    SI,BX            ; Go to next file
  417.  
  418.         Push    BX            ; Save these registers
  419.         Push    CX
  420.         Mov    DX,Offset PauseMessage    ; Test to print
  421.         Mov    CX,Offset PauseMsgEnd - Offset PauseMessage
  422.                         ; Number of characters
  423.         Mov    BX,2            ; Standard ERROR Output
  424.         Mov    AH,40h            ; Display to screen
  425.         Int    21h            ; By calling DOS 
  426.         Pop    CX            ; Retrieve pushed registers 
  427.         Pop    BX
  428.  
  429.         Mov    AH,8            ; Wait for character
  430.         Int    21h            ; Through DOS call
  431.  
  432.         Call    CRLF            ; Go to next line 
  433.  
  434.         Loop    SetIncrement        ; And recalculate increment
  435.  
  436. AllFinished:    Pop    DS            ; Done with subroutine
  437.         Pop    SI
  438.         Pop    DX
  439.         Pop    BX
  440.         Ret                ; So return to caller
  441.  
  442. ;    Display Routines
  443. ;    ----------------
  444.  
  445. PrintChar:    Mov    DL,AL            ; Print character in AL
  446.         Mov    AH,2            ; By simple DOS call
  447.         Int    21h
  448.         Ret                ; And return
  449.  
  450. CRLF:        Mov    AL,13            ; Print a carriage return
  451.         Call    PrintChar
  452.         Mov    AL,10            ; And a line feed
  453.         Call    PrintChar
  454.         Ret                ; And return
  455.  
  456. PrintString:    Lodsb                ; Get character from SI
  457.         Call    PrintChar        ; Print it
  458.         Loop    PrintString        ; Do that CX times
  459.         Ret                ; And return
  460.  
  461. PrintFile:    Push    CX            ; Save the counter
  462.         Mov    CX,32            ; Bytes for Name, Size, & Date
  463.         Call    PrintString        ; Print it    
  464.         Inc    SI            ; Skip one space before time
  465.         Mov    CX,6            ; Bytes for Time
  466.         Call    PrintString        ; It's a print!
  467.         Pop    CX        
  468.         Ret                ; And return
  469.  
  470. FileBuffer    Label    Byte            ; Points to end of code
  471.  
  472. CSEG        EndS                ; End of segment
  473.  
  474.         End    Entry            ; Denotes entry point
  475.