home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol6n02.zip / DIRCOMP.ASM next >
Assembly Source File  |  1987-12-13  |  13KB  |  427 lines

  1. ;    DIRCOMP.ASM -- Lists two directories side by side
  2. ;    =================================================
  3.  
  4. CSEG        Segment
  5.         Assume    CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
  6.         Org    0080h
  7. Parameter    Label    Byte        ; Parameter is here
  8.         Org    0100h
  9. Entry:        Jmp    Begin        ; Entry Point
  10.  
  11. ;    Most Data (some more at end of program)
  12. ;    ---------------------------------------
  13.  
  14.         db    "Copyright 1986 Ziff-Davis Publishing Co.",1Ah
  15.         db    " Programmed by Charles Petzold ",1Ah
  16. SyntaxMsg    db    "Syntax: DIRCOMP filespec filespec$"
  17. DosVersMsg    db    "DIRCOMP: Needs DOS 2.0 +$"
  18. FileSpecMsg    db    "DIRCOMP: Bad file name$"
  19. TooManyMsg    db    "DIRCOMP: Too many files$"
  20. MemAllocMsg    db    "DIRCOMP: Not enough memory$"
  21. Delimiters    db    9,' ,;='
  22. FileList1    dd    0, ?        ; Storage of found files
  23. FileList2    dd    0, ?
  24. FileCount1    dw    0        ; Count of found files
  25. FileCount2    dw    0
  26. Append        db    '\*.*', 0
  27.  
  28. ;    Check DOS Version
  29. ;    -----------------
  30.  
  31. Begin:        Mov    AH, 30h            ; Check for DOS Version
  32.         Int    21h            ;   through DOS call
  33.         Cmp    AL, 2            ; See if it's 2.0 or above
  34.         Jae    DosVersOK        ; If so, continue
  35.         Mov    DX, Offset DosVersMsg    ; Error message
  36.  
  37. ErrorExit:    Mov    AH, 9            ; Print String function call
  38.         Int    21h            ; Do it
  39.         Int    20h            ; And exit prematurely
  40.  
  41. ;    Parse Command Line to get file specifications
  42. ;    ---------------------------------------------
  43.  
  44. DosVersOK:    Cld                ; Directions forward
  45.         Mov    SI, Offset Parameter    ; Parameter string
  46.         Lodsb                ; Length of Parameter
  47.         Mov    BL, AL            ; Make BX the length
  48.         Sub    BH, BH
  49.         Mov    Word Ptr [SI + BX], 0D20h    ; Put blank at end
  50.     
  51.         Mov    DI, Offset FileSpec1    ; Destination of first spec
  52.         Call    GetFileSpec        ; Transfer it and fix it up
  53.         Mov    DI, Offset FileSpec2    ; Destination of second spec
  54.         Call    GetFileSpec        ; Transfer it and fix it up
  55.  
  56. ;    De-Allocate rest of memory
  57. ;    --------------------------
  58.  
  59.         Mov    DX, Offset MemAllocMsg    ; Possible error message
  60.         Mov    SP, Offset StackTop    ; Bring in stack pointer
  61.         Mov    BX, SP            ; Also end of needed memory
  62.         Add    BX, 15            ; Add 15 for truncation
  63.         Mov    CL, 4            ; Shift 4 bits right
  64.         Shr    BX, CL
  65.         Mov    AH, 4Ah            ; Change memory size
  66.         Int    21h            ;   through DOS
  67.         Jc    ErrorExit        ; If problem, terminate
  68.  
  69. ;    Find Files from file specification
  70. ;    ----------------------------------
  71.  
  72.         Mov    DX, Offset DTABuffer    ; Set File Find buffer
  73.         Mov    AH, 1Ah            ;   by calling DOS
  74.         Int    21h
  75.  
  76.         Mov    DX, Offset FileSpec1    ; First file specification
  77.         Call    GetFilesAndSort        ; Do as it says
  78.         Mov    Word Ptr [FileList1 + 2], AX    ; Segment of file list
  79.         Mov    [FileCount1], CX    ; Number of files
  80.  
  81.         Mov    DX, Offset FileSpec2    ; Second file specification
  82.         Call    GetFilesAndSort        ; Do it again
  83.         Mov    Word Ptr [FileList2 + 2], AX    ; Segment of file list
  84.         Mov    [FileCount2], CX    ; Number of files
  85.  
  86. ;    Now Display List on Screen
  87. ;    --------------------------
  88.  
  89. DoAnother:    Lea    DI, DisplayString    ; Destination of display line
  90.         Mov    AL, ' '            
  91.         Cmp    [FileCount1],0        ; See if any more left
  92.         Jz    FirstColDone        ; If so, first column is blank
  93.         Cmp    [FileCount2],0        ; See if second is done
  94.         Jz    ListOnly1        ; If so, 2nd column is blank
  95.         Push    SI
  96.         Push    DI
  97.         Push    DS
  98.         Push    ES
  99.         Les    DI, [FileList2]        ; Address of second list
  100.         Lds    SI, [FileList1]        ; Address of first list
  101.         Mov    CX, 12            ; Number of bytes to compare
  102.         Repz    Cmpsb            ; Compare them
  103.         Pop    ES            ; Get back registers
  104.         Pop    DS
  105.         Pop    DI
  106.         Pop    SI
  107.         Jb    ListOnly1        ; If file 1 < file 2, list 1 
  108.         Ja    ListOnly2        ; If file 1 > file 2, list 2
  109.         Call    ListFile1        ; Put first in display string
  110.         Stosb                ; Put a blank after it
  111.         Jmp    Short DoSecond        ; Now do second file
  112.  
  113. FirstColDone:    Cmp    [FileCount2], 0        ; See if second done also
  114.         Jz    AllDone            ; If so, we're done
  115.  
  116. ListOnly2:    Mov    CX, 40            ; If not, store 40 blanks
  117.         Rep    Stosb
  118.  
  119. DoSecond:    Call    ListFile2        ; Put 2nd file in display str
  120.         Jmp    Short WriteCRLF        ; And append a CR/Lf
  121.  
  122. ListOnly1:    Call    ListFile1        ; Put 1st file in display str
  123.         Mov    CX, 40            ; Blank out second half
  124.         Rep    Stosb
  125.  
  126. WriteCRLF:    Mov    AX, 0A0Dh        ; Put CR/LF at end of string
  127.         Stosw
  128.  
  129. SpillOut:    Lea    DX, DisplayString    ; Address of display string
  130.         Mov    CX, 81            ; Number of characters
  131.         Mov    BX, 1            ; Standard output
  132.         Mov    AH, 40h            ; Write to screen
  133.         Int    21h            ;   through DOS
  134.         Jmp    DoAnother        ; And do the next one
  135.  
  136. AllDone:    Int    20h            ; All done -- terminate
  137.  
  138. ;    SUBROUTINE: Get File Spec (uses DI to point to destination)
  139. ;    -----------------------------------------------------------
  140.  
  141. GetFileSpec:    Mov    DX, DI            ; Save pointer in DX
  142.         
  143. Search:        Call    ScanParam        ; Check next byte
  144.         Je    Search            ; If delimiter, keep searching
  145.         
  146. SearchEnd:    Stosb                ; Save the character
  147.         Call    ScanParam        ; Check the next byte
  148.         Jne    SearchEnd        ; If not delimiter, continue
  149.         Mov    Byte Ptr [DI], 0    ; Make it an ASCIIZ string
  150.         Push    SI            ; Save parameter pointer
  151.         Mov    SI, 1 + Offset Append    ; Set to *.* string
  152.         Mov    CX, 4            ; Possible 4 bytes to move
  153.         Cmp    Byte Ptr [DI - 1], ':'    ; Do it if last character is :
  154.         Jz    AppendStuff
  155.         Cmp    Byte Ptr [DI - 1], '\'    ; Or if last character is \
  156.         Jz    AppendStuff
  157.         Mov    AX, 4300h        ; Get file attribute
  158.         Int    21h            ;   through DOS
  159.         Jc    FixUpDone        ; If error, do no more
  160.         Test    CL, 10h            ; See if it's directory
  161.         Jz    FixUpDone        ; If not, do no more
  162.         Dec    SI            ; If so, append \*.*
  163.         Inc    CX            ;   which has five characters
  164.  
  165. AppendStuff:    Rep    Movsb            ; Append string to file spec
  166.  
  167. FixUpDone:    Pop    SI            ; And done with this stuff
  168.         Ret
  169.  
  170. ;    SUBROUTINE: Scan Parameter
  171. ;    --------------------------
  172.  
  173. ScanParam:    Push    DI            ; Save destination pointer
  174.         Lodsb                ; Get byte from parameter
  175.         Cmp    AL, 13            ; See if end of parameter
  176.         Jne    NotAtEnd        ; If so, got an error
  177.         Mov    DX, Offset SyntaxMsg    ; Load up error message
  178.         Jmp    ErrorExit        ;    and exit
  179.  
  180. NotAtEnd:    Mov    DI, Offset Delimiters    ; Check if delimiter
  181.         Mov    CX, 5            ; There are 5 of them
  182.         Repne    Scasb            ; Scan the string
  183.         Pop    DI            ; Get back pointer
  184.         Ret                ; And return
  185.  
  186. ;    SUBROUTINE: Get Files and Sort
  187. ;    ------------------------------
  188.  
  189. GetFilesAndSort:Push    ES
  190.         Mov    BX, 1000h        ; Try to allocate 64K memory
  191.         Mov    AH, 48h            ;   through DOS
  192.         Int    21h
  193.         Jnc    AllocateOK        ; If no error, we've got it
  194.         Mov    AH, 48h            ; Otherwise allocate
  195.         Int    21h            ;   as much as possible
  196.  
  197. AllocateOK:    Mov    CL, 4            ; Turn BX into an offset
  198.         Shl    BX, CL
  199.         Sub    BX, 20            ; Take away 20 bytes
  200.         Mov    ES, AX            ; Set ES to memory segment
  201.         Sub    DI, DI            ; Point to beginning
  202.         Sub    BP, BP            ; File Counter
  203.         Mov    CX, 06h            ; Normal, hidden, system files
  204.         Mov    AH, 4Eh            ; Find first file 
  205.  
  206. FindFile:    Int    21h            ; Call DOS to find file
  207.         Jnc    Continue        ; If no error continue
  208.         Cmp    AX, 18            ; If no more files
  209.         Jz    NoMoreFiles        ;   get out of the loop
  210.         Mov    DX, Offset FileSpecMsg    ; Error message otherwise
  211.         Jmp    ErrorExit        ; Exit and print message
  212.  
  213. Continue:    Cmp    DI, BX            ; See if end of segment
  214.         Jb    StillOK            ; If not, continue
  215.  
  216. TooManyFiles:    Mov    DX, Offset TooManyMsg    ; Otherwise error message
  217.         Jmp    ErrorExit        ; And terminate
  218.  
  219. StillOK:    Inc    BP            ; Kick up file counter
  220.         Mov    SI, 30+Offset DTABuffer    ; Points to filename
  221.         Mov    CX, 12            ; 12 bytes to transfer
  222.  
  223. TransName:    Lodsb                ; Get a byte
  224.         Or    AL, AL            ; See if it's zero
  225.         Jz    NameDone        ; If so, transfer done
  226.         Cmp    AL, '.'            ; See if it's period
  227.         Jnz    NotPeriod        ; If not keep going
  228.         Sub    CX, 3            ; If period, adjust counter
  229.         Mov    AL, ' '            ; Pad names with blanks
  230.         Rep    Stosb
  231.         Add    CX, 3            ; Re-adjust counter
  232.         Jmp    TransName        ; And continue
  233.  
  234. NotPeriod:    Stosb                ; If not period, just store it
  235.         Loop    TransName        ; And keep going
  236.  
  237. NameDone:    Mov    AL, ' '            ; Pad end of name with blanks
  238.         Rep    Stosb
  239.         Mov    SI, 22+Offset DTABuffer    ; Point to time/date/size
  240.         Mov    CX, 4            ; Save that stuff too
  241.         Rep    Movsw
  242.         Mov    AH, 4Fh            ; Find next file
  243.         Jmp    FindFile
  244.  
  245. NoMoreFiles:    Mov    BX, DI            ; End of file storage
  246.         Add    BX, 15            ; Convert to paragraph
  247.         Mov    CL, 4
  248.         Shr    BX, CL
  249.         Mov    AH, 4Ah            ; Re-adjust memory
  250.         Int    21h
  251.  
  252. ;    Sort Files
  253. ;    ----------
  254.  
  255.         Push    DS            ; Save DS
  256.         Push    ES
  257.         Pop    DS            ; Point DS to files
  258.         Sub    DI, DI            ; This is the beginning
  259.         Mov    CX, BP            ; Number of files to sort
  260.         Jcxz    AllSorted        ; If no files, we're done
  261.         Dec    CX            ; Loop needs one less than CX
  262.         Jcxz    AllSorted        ; But zero means only one file
  263.  
  264. SortLoop1:    Push    CX            ; Save the file counter
  265.         Mov    SI, DI            ; Set source to destination
  266.  
  267. SortLoop2:    Add    SI, 20            ; Set source to next file
  268.         Push    CX            ; Save the counter,
  269.         Push    SI            ;    compare source,
  270.         Push    DI            ;    and compare destination
  271.         Mov    CX, 20            ; 20 characters to compare
  272.         Repz    Cmpsb            ; Do the compare
  273.         Jae    NoSwitch        ; Jump if already in order
  274.         Pop    DI            ; Get back these registers
  275.         Pop    SI
  276.         Push    SI            ; And push them again for move
  277.         Push    DI
  278.         Mov    CX, 20            ; 20 characters
  279.  
  280. SwitchLoop:    Mov    AL, ES:[DI]        ; Character from destination 
  281.         Movsb                ; Source to destination
  282.         Mov    DS:[SI - 1], AL        ; Character to source
  283.         Loop    SwitchLoop        ; For the rest of the line
  284.  
  285. NoSwitch:    Pop    DI            ; Get back the registers
  286.         Pop    SI
  287.         Pop    CX
  288.         Loop    SortLoop2        ; And loop for next file
  289.         Pop    CX            ; Get back file counter 
  290.         Add    DI, 20            ; Compare with next file
  291.         Loop    SortLoop1        ; And loop again
  292.  
  293. AllSorted:    Pop    DS            ; Get back to normal
  294.         Mov    AX, ES            ; File segment in AX
  295.         Pop    ES
  296.         Mov    CX, BP            ; File count in CX
  297.         Ret
  298.  
  299. ;    SUBROUTINES for listing files on screen
  300. ;    ---------------------------------------
  301.  
  302. ListFile1:    Push    DS
  303.         Lds    SI, [FileList1]        ; Set to address of list
  304.         Call    ListFile        ; Put it into DisplayString
  305.         Pop    DS
  306.         Mov    Word Ptr [FileList1], SI    ; Save new pointer
  307.         Dec    [FileCount1]        ; Decrement count
  308.         Ret
  309.         
  310. ListFile2:    Push    DS
  311.         Lds    SI, [FileList2]        ; Set to address of list
  312.         Call    ListFile        ; Put it into DisplayString
  313.         Pop    DS
  314.         Mov    Word Ptr [FileList2], SI    ; Save new pointer
  315.         Dec    [FileCount2]        ; Decrement count
  316.         Ret
  317.  
  318. ListFile:    Push    AX
  319.         Push    SI
  320.         Push    DI
  321.         Mov    CX, 12        ; 12 characters in file name
  322.         Rep    Movsb        ; Transfer them
  323.         Mov    AL, ' '        ; Blank out the rest
  324.         Mov    CX, 27
  325.         Rep    Stosb
  326.  
  327.         Sub    DI, 6        ; Point to time destination
  328.         Lodsw            ; Get the coded time
  329.  
  330.         Mov    BL, 01Fh    ; AND mask for hours
  331.         Mov    BH, '0'        ; Zero-blank indicator
  332.         Mov    CL, 11        ; Shift value for hours
  333.         Sub    DL, DL        ; Offset for hours
  334.         Mov    DH, ':'        ; Following character
  335.         Call    DateTime    ; Do the transfer routine    
  336.  
  337.         Mov    BX, 3Fh        ; Zero OK / AND Mask for minutes
  338.         Mov    CL, 5        ; Shift value of minutes
  339.         Mov    DH, ' '        ; Following character
  340.         Call    DateTime    ; Do the transfer routine
  341.  
  342.         Sub    DI, 16        ; Point to date destination
  343.         Lodsw            ; Get the coded date
  344.  
  345.         Mov    BL, 0Fh        ; AND mask for month
  346.         Mov    BH, '0'        ; Zero-blank indicator
  347.         Mov    CL, 5        ; Shift value for month
  348.         Mov    DH, '-'        ; Following character
  349.         Call    DateTime    ; Do the transfer routine
  350.  
  351.         Mov    BX, 1Fh        ; Zero OK / AND mask for day
  352.         Mov    CL, 0        ; Shift value for day
  353.         Call    DateTime    ; Do the transfer routine
  354.  
  355.         Mov    BL, 7Fh        ; AND mask for year
  356.         Mov    CL, 9        ; Shift value for year
  357.         Mov    DL, 80        ; Offset for year
  358.         Mov    DH, ' '        ; Following character
  359.         Call    DateTime    ; Do the transfer routine
  360.  
  361.         Sub    DI, 12        ; Point to end of file size space
  362.         Lodsw            ; Get low word
  363.         Mov    DX, AX        ; Save it in DX
  364.         Lodsw            ; AX is high word, DX low word
  365.         Mov    BX, 10        ; Will divide by 10 for ASCII
  366.         Std            ; Direction backward
  367.  
  368. AsciiLoop:    Mov    CX, DX        ; Save low word in CX
  369.         Sub    DX, DX        ; Zero out DX for division
  370.         Div    BX        ; AX = quotient, DX = remainder
  371.         Xchg    AX, CX        ; Now AX = low word, CX = quotient1
  372.         Div    BX        ; AX = quotient2, DX = remainder
  373.         Xchg    AX, DX        ; AX = remainder, DX = quotient2
  374.         Add    AL, '0'        ; Adjust for ASCII
  375.         Stosb            ; Store it
  376.         Mov    AX, CX        ; See if zero is left
  377.         Or    CX, DX
  378.         Jnz    AsciiLoop    ; If not, continue
  379.  
  380.         Cld            ; Get back to normal
  381.         Pop    DI
  382.         Pop    SI
  383.         Pop    AX
  384.         Add    SI, 20        ; Next file in list
  385.         Add    DI, 39        ; Next byte in destination
  386.         Ret
  387.  
  388. ;    SUBROUTINE: Date and Time Display
  389. ;    ---------------------------------
  390.  
  391. DateTime:    Push    AX
  392.         Push    BX
  393.         Push    CX
  394.         Push    DX
  395.         Shr    AX, CL        ; Shift word left by CL bits
  396.         And    AL, BL        ; AND it with BL mask
  397.         Add    AL, DL        ; Offset it by DL
  398.         Sub    AH, AH        ; Zero out high byte
  399.         Mov    BL, 10        ; Divide by 10
  400.         Div    BL
  401.         Add    AX, '00'    ; Convert to ASCII
  402.         Cmp    AL, BH        ; Check Zero-Blank
  403.         Jnz    LeadingNonZero    
  404.         Mov    AL, ' '        ; Put in blank instead of zero
  405.  
  406. LeadingNonZero:    Stosw            ; Store the two bytes
  407.         Mov    AL, DH        ; Get following character
  408.         Stosb            ; Store that also
  409.         Pop    DX
  410.         Pop    CX
  411.         Pop    BX
  412.         Pop    AX
  413.         Ret
  414.  
  415. ;    Variable length data stored at end
  416. ;    ----------------------------------
  417.  
  418.         Even
  419. FileSpec1    Label    Byte
  420. FileSpec2    equ    FileSpec1 + 80
  421. DTABuffer    equ    FileSpec2 + 80
  422. DisplayString    equ    DTABuffer + 43
  423. EndOfData    equ    DisplayString + 81
  424. StackTop    equ    EndOfData + 200h
  425. CSEG        EndS                ; End of the segment
  426.         End    Entry            ; Denotes entry point
  427.