home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / dirutl / ddir0789.arc / DDIR.ASM next >
Encoding:
Assembly Source File  |  1989-05-24  |  13.1 KB  |  447 lines

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