home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / utility / deldup23.zip / DELDUPE.ASM < prev    next >
Assembly Source File  |  1989-03-01  |  25KB  |  933 lines

  1.     page    74,132
  2.     title    DELDUPE - Delete duplicate and/or older files
  3.     comment |
  4.  
  5. Syntax:
  6.     DELDUPE  directory-to-delete  [master-directory]
  7.          [/O] [/T] [/S] [/V] [/N]
  8.  
  9.     Command line options:
  10.       /O    delete older files
  11.       /N    delete files of same name regardless of date/time/size
  12.       /S    delete similiar files, same date/time but different sizes
  13.       /T    test mode, list duplicates but do not delete
  14.       /V    verify, ask for permission to delete each file
  15.       /P    pause when screen fills
  16.  
  17. License:
  18.     DELDUPE 2.3, Copyright (c) Vernon D. Buerg 1987-89. ALL RIGHTS RESERVED.
  19.  
  20.     DELDUPE is free, but it is a copyrighted work and may be distributed
  21.     only pursuant to this license.
  22.  
  23.     Permission is hereby granted to reproduce and disseminate DELDUPE so
  24.     long as:
  25.  
  26.        (1)    No remuneration of any kind is received in exchange; and
  27.  
  28.        (2)    Distribution is without ANY modification to the contents
  29.         of DELDUPE.COM, DELDUPE.ASM and all accompanying
  30.         documentation and/or support files, including the
  31.         copyright notice and this license.
  32.  
  33.     No copy of DELDUPE may be distributed without including a copy
  34.     of this license.
  35.  
  36.     Any other use is prohibited without express, written permission in
  37.     advance.
  38.  
  39.         Vernon D. Buerg
  40.         139 White Oak Circle
  41.         Petaluma, CA  94952
  42.  
  43.         CompuServe: 70007,1212    (Go IBMCOM)
  44.         Data/BBS:   (707) 778-8944                |
  45.  
  46.     page
  47. ;
  48. ;    data area structures
  49.  
  50. psp        struc            ; program segment prefix
  51. psp_int_20    db    0cdh,020h    ; int 20 instruction
  52. psp_top     dw    ?        ; top of memory in paragraph form
  53. psp_resvl    dw    ?        ; reserved
  54. psp_bytes    dw    ?,?        ; bytes available in segment
  55.         db    118 dup (?)    ; unused
  56. psp_parm_len    db    ?        ; characters in parameter list
  57. psp_parms    db    127 dup (?)    ; command parameters
  58. psp        ends
  59.  
  60.  
  61. dta        struc            ; data transfer area
  62. dtarsvd     db    21 dup (?)    ;  reserved for DOS
  63. dtaattr     db    ?        ;  attribute found
  64. dtatime     dw    ?        ;  file's time
  65. dtadate     dw    ?        ;  file's date
  66. dtasize     dd    ?        ;  file's size (lo,hi)
  67. dtaname     db    13 dup (?)    ;  file name and ext, asciiz form
  68. dta        ends
  69.  
  70.  
  71. files        struc            ; file entry in table
  72. filetime    dw    ?        ;  file's time
  73. filedate    dw    ?        ;  file's date
  74. filesize    dd    ?        ;  file's size (lo,hi)
  75. filename    db    13 dup (?)    ;  file name and ext, asciiz form
  76. files        ends
  77.  
  78. file_len    equ    size files    ; size of each file entry
  79.  
  80. bios        segment at 40h        ; dos data area
  81.         org    84h        ;
  82. ega_rows    label    byte        ; rows on screen
  83. bios        ends
  84.  
  85.     page
  86. ;
  87. ;    main program - data areas, equates, and constants
  88.  
  89. cseg    segment public para 'code'
  90.     assume    cs:cseg, ds:cseg, es:nothing
  91.     org    100h
  92.  
  93. deldupe proc    far
  94.     jmp    start            ; skip around data areas
  95.  
  96.  
  97. ;    equates
  98.  
  99. zero    equ    0            ; constant
  100. one    equ    1            ; constant
  101.  
  102. bs    equ    8            ; backspace
  103. tab    equ    9            ; a tabby
  104. cr    equ    13            ; and a carriage return
  105. lf    equ    10            ; a line feed
  106. eof    equ    26            ; end of file marker
  107. blank    equ    32            ; a space
  108.  
  109. idos    equ    21h            ; dos interrupt 21h functions
  110.  dconio equ    08h            ; direct console i/o
  111.  pstrng equ    09h            ; print string
  112.  bufcon equ    0ah            ; buffered keyboard input
  113.  select equ    0eh            ; select disk
  114.  setdta equ    1ah            ; set data transfer area
  115.  curdsk equ    19h            ; get current disk
  116.  chdir    equ    3bh            ; change current directory
  117.  write    equ    40h            ; write to a file or handle
  118.  delete equ    41h            ; delete a file
  119.  getdir equ    47h            ; get current directory
  120.  ffirst equ    4eh            ; find first matching file
  121.  fnext    equ    4fh            ; find next matching file
  122.  
  123. switch_char    equ    '/'             ; delimiter for command line switches
  124. path_char    equ    '\'             ; delimiter for path names
  125. drive_char    equ    ':'             ; delimiter for drive letters
  126. stopper     equ    255        ; ends print string text
  127.  
  128. date    record    year:7,month:4,day:5    ; dos packed date mask
  129. time    record    hour:5,minute:6,sec:5    ; dos packed time mask
  130.  
  131.     page
  132. ;
  133. ;    messages
  134.  
  135. usage    db    cr,'   '                ; overwrite the jmp
  136.     db    cr,lf,'DELDUPE 2.3, Copyright (c) 1987-89, Vernon D. Buerg. ALL RIGHTS RESERVED.'
  137.     db    cr,lf
  138.     db    cr,lf,'Usage:'
  139.     db    cr,lf,tab,    'd:\deldupe directory-to-delete [master-directory]'
  140.     db    cr,lf,tab,tab,tab,                ' [/O] [/T] [/S] [/V] [/P] [/N]'
  141.     db    cr,lf
  142.     db    cr,lf,tab,    'Supply drive and \ for each directory.'
  143.     db    cr,lf,tab,    'If master-directory is omitted, the current directory is used.'
  144.     db    cr,lf
  145.     db    cr,lf,tab,    '/O  delete Older files of same name'
  146.     db    cr,lf,tab,    '/S  delete Similar files (diff size only)'
  147.     db    cr,lf,tab,    '/T  display filenames but do not delete (Test)'
  148.     db    cr,lf,tab,    '/V  Verify the deletion of each file'
  149.     db    cr,lf,tab,    '/P  Pause when screen fills'
  150.     db    cr,lf,tab,    '/N  delete files of same Name'
  151. null    db    cr,lf,'$'
  152.     db    bs,blank,eof        ; end of usage display for TYPE
  153.  
  154. cooking db    cr,lf,'Analyzing master directory ... $'
  155.  
  156. errmsg1 db    cr,lf,'No matching files found!',cr,lf,'$'
  157. errmsg2 db    cr,   'No duplicate or older files to delete.',cr,lf,'$'
  158.  
  159. inform1 db    'Same   '               ; identical date/time/size
  160. inform2 db    'Older  '               ; earlier date/time
  161. inform3 db    'Similar'               ; same date, diff size
  162.  
  163. donemsg db    cr,lf            ; final summary message
  164. dcount    db    '         file(s)     '
  165. dsize    db    '         bytes$'
  166.  
  167. more    db    cr,lf,'More>','$'       ; full screen prompt
  168. prompt    db    '- delete? $'           ; verification prompt
  169. reply    db    2,0            ; buffered console read buffer
  170. answer    db    0,0            ; their answer
  171.  
  172. titles    db    cr,tab,tab,tab,           '- Master directory -   -- Old directory ---'
  173.     db    cr,lf,'Reason   Filename       Bytes    Last change   Bytes    Last change'
  174.     db    stopper
  175.  
  176. prtline db    cr,lf            ; detail print line
  177. prtwhy    db    'Similar  '             ; reason for deleting
  178. prtname db    12 dup (' ')            ; file name and ext
  179. oldsize db    '         '             ; file's size
  180. olddate db    '         '             ; file's date
  181. oldtime db    '     '                 ; file's time
  182. prtstop label    byte            ; stop line here if same
  183. newsize db    '         '             ; file's size
  184. newdate db    '         '             ; file's date
  185. newtime db    '     '                 ; file's time
  186.     db    stopper
  187. prt_len equ    $-prtline        ; length of print line
  188.  
  189.     page
  190. ;
  191. ;    constants and work areas
  192.  
  193. flags    db    0            ; processing options
  194.  older     equ     1            ; O = delete older version of files
  195.  test     equ     2            ; T = display but don't really delete
  196.  similar equ     4            ; S = delete if same date/time but diff size
  197.  verify  equ     8            ; V = ask to confirm each delete
  198.  pause     equ     10h            ; P = pause when screen fills
  199.  newer     equ     20h            ; N = delete regardless of date/time
  200.  first     equ     40h            ; set when headings printed 1st time
  201.  
  202. max    dw    3000            ; maximum table entries (dynamic)
  203. count    dw    0            ; total number of table entries used
  204. mcount    dw    0            ; number of entries for master dir
  205. ocount    dw    0            ; number of entries for old dir
  206. deleted dw    0            ; number of files deleted
  207. delsize dw    0,0            ; sum of deleted file sizes
  208. old_table dw    0            ; ptr to first table entry for old dir
  209.  
  210. msg1    db    cr,lf,'Old path not found -- '
  211. oldpath db    76 dup (0),'$'          ; directory to delete from
  212.  
  213. msg2    db    cr,lf,'New path not found -- '
  214. newpath db    76 dup (0),'$'          ; master directory
  215.  
  216. global    db    '*.*',0                 ; for find first/next
  217. curdrv    db    0            ; current drive number
  218. crtrows db    0            ; rows on screen
  219.  
  220. dtawork db    48 dup (0)        ; data transfer area
  221.  
  222. olddrv    db    ' :\'                   ; original path for oldpath drive
  223. olddir    db    64 dup (0)        ; its current directory
  224.  
  225. newdrv    db    ' :\'                   ; original path for newpath drive
  226. newdir    db    64 dup (0)        ; its current directory
  227.  
  228.     page
  229. ;
  230. ;    set switches from command line
  231.  
  232. start:
  233.     push    es            ; set dos data area
  234.     mov    ax,bios         ; segment address
  235.     mov    es,ax            ;
  236.     mov    al,byte ptr es:ega_rows ; dos rows on screen
  237.     mov    ah,24            ; default max rows
  238.     or    al,al            ; is row value ok?
  239.     jz    start1            ; no, use default
  240.     mov    ah,al            ; yes,
  241. start1: sub    ah,2            ; compensate for heading
  242.     mov    byte ptr crtrows,ah    ; set max rows on screen
  243.     pop    es            ;
  244.  
  245.     mov    dx,offset dtawork    ; use local dta
  246.     mov    ah,setdta        ; set disk transfer area
  247.     int    idos            ;
  248.  
  249.     mov    ah,curdsk        ; get current disk
  250.     int    idos            ;
  251.     mov    curdrv,al        ; and save for exit
  252.  
  253.     lea    sp,table        ; set local stack
  254.     mov    ax,word ptr ds:psp_bytes ; size of segment
  255.     sub    ax,pgmsize        ;  less program size
  256.     sub    dx,dx            ;
  257.     mov    cx,file_len        ; size of each table entry
  258.     div    cx            ;  to get maximum entries
  259.     mov    max,ax            ;
  260.  
  261.     mov    si,offset psp_parm_len    ; point to command line
  262.     sub    cx,cx            ; to receive command line length
  263.     lodsb
  264.     or    cl,al            ; any command line?
  265.     jnz    switches        ; yes, continue
  266.  
  267. error1:
  268.     mov    dx,offset usage     ; operands are missing
  269. sendmsg:
  270.     mov    ah,pstrng        ; print final message
  271.     int    idos            ;
  272.     mov    ah,chdir        ; restore current directory
  273.     mov    dx,offset olddrv    ;  for oldpath drive
  274.     int    idos            ;
  275.     mov    ah,chdir        ; restore current directory
  276.     mov    dx,offset newdrv    ;  for newpath drive
  277.     int    idos            ;
  278.     mov    dl,curdrv        ; restore current drive
  279.     mov    ah,select        ; via select disk
  280.     int    idos            ;
  281.     int    20h            ; exit as is
  282.  
  283. switches:
  284.     mov    di,offset psp_parms    ; offset to command parameters
  285. switches0:
  286.     mov    al,switch_char        ; see if ANY switches
  287.     repne    scasb
  288.     jne    switched        ; none, skip next
  289.     jcxz    switched        ; no more data
  290.     mov    byte ptr -1[di],cr    ; terminate command line at first /
  291.     cmp    byte ptr -2[di],blank    ;
  292.     jne    switchesa        ;
  293.     mov    byte ptr -2[di],cr    ;
  294. switchesa:
  295.     mov    si,di            ; point to next char
  296.     lodsb                ; get char following switch char
  297.     cmp    al,'a'                  ;  and make it upper case
  298.     jb    switches1        ;
  299.     sub    al,blank        ;
  300. switches1:
  301.     cmp    al,'O'                  ; delete older files?
  302.     jne    switches2        ;
  303.     or    flags, older        ;
  304. switches2:
  305.     cmp    al,'T'                  ; display but don't delete?
  306.     jne    switches3        ;
  307.     or    flags, test        ;
  308. switches3:
  309.     cmp    al,'S'                  ; delete similar files?
  310.     jne    switches4        ;
  311.     or    flags,similar        ;
  312. switches4:
  313.     cmp    al,'P'                  ; want to pause when screen fills?
  314.     jne    switches5        ;
  315.     or    flags, pause        ;
  316. switches5:
  317.     cmp    al,'V'                  ; want to verify each delete?
  318.     jne    switches6        ;
  319.     or    flags, verify        ;
  320. switches6:
  321.     cmp    al,'N'                  ; want to delete matching names?
  322.     jne    switches7        ;
  323.     or    flags, newer        ;
  324. switches7:
  325.     jcxz    switched        ; any more operands?
  326.     jmp    switches0        ; yup
  327.  
  328.     page
  329. ;
  330. ;    get path names for old and new directories
  331.  
  332. switched:
  333.     mov    si,offset psp_parms    ; point to command line again
  334.     mov    cl,byte ptr ds:[psp_parm_len] ; get length back
  335. parm1:
  336.     lodsb                ; next char
  337.     cmp    al,blank        ; skip leading blanks
  338.     je    parm1a            ;
  339.     cmp    al,tab            ; skip tabs, too
  340.     jne    parm2            ;
  341. parm1a: loop    parm1            ;
  342.     jmp    error1            ; operand(s) missing
  343.  
  344. parm2:
  345.     mov    di,offset oldpath    ; target for old path name
  346.     sub    cx,1            ; account for last lodsb
  347.     jg    parm3            ; if more to process
  348.     jmp    error1            ; operand(s) missing
  349. parm3:
  350.     stosb                ; previous char
  351.     lodsb                ; next char
  352.     cmp    al,blank        ; have operand separator?
  353.     jbe    parm4            ; yes, have first op
  354.     loop    parm3            ;
  355.     stosb                ;
  356.     jmp    short parm2a        ; no second operand, use curdir
  357.  
  358. parm4:
  359.     mov    di,offset newpath    ; target for master path name
  360.     jcxz    parm2a            ; if no second operand
  361. parm5:
  362.     lodsb                ; skip intervening delimiters
  363.     cmp    al,blank        ;
  364.     je    parm6            ;
  365.     cmp    al,cr            ; end of parameters?
  366.     je    parm2a            ; yes, just one operand
  367.     cmp    al,tab            ; skip tabs
  368.     jne    parm7            ;
  369. parm6:    loop    parm5            ; until no more command parameters
  370.  
  371. parm2a:
  372.     mov    di,offset newpath    ; target for master path name
  373.     mov    ah,curdsk        ; get current drive
  374.     int    idos            ;
  375.     mov    dl,al            ; drive letter for oldpath
  376.     add    al,'A'                  ; make into letter
  377.     stosb                ; set master path name
  378.     mov    ax,'\:'                 ;  to current drive
  379.     stosw                ;
  380.     inc    dl            ; letter to drive number
  381.     mov    ah,getdir        ; get current directory
  382.     mov    si,di            ;
  383.     int    idos            ;
  384.     mov    cx,64            ; maximum length to find end of name
  385.     lodsb                ; first char of path name
  386.  
  387. parm7:                    ; copy 2nd path name to 'newpath'
  388.     stosb                ; its first/next char
  389.     lodsb                ; get next command line char
  390.     cmp    al,cr            ; end of it?
  391.     jbe    check1            ; yes, have both operands now
  392.     loop    parm7
  393.  
  394.     page
  395. ;
  396. ;    get and save current directory name for drive
  397. ;    containing old and new (master) directories
  398.  
  399. check1:                 ; check if path names are valid
  400.     mov    ah,curdsk        ; get current drive
  401.     int    idos            ;
  402.     add    al,'A'                  ; convert to drive letter
  403.     mov    byte ptr olddrv,al    ;  and save it
  404.     mov    word ptr olddrv+1,'\:'  ;   in original
  405.     mov    byte ptr newdrv,al    ;    directory names
  406.     mov    word ptr newdrv+1,'\:'  ;     with delimiters
  407.  
  408.     mov    dl,0            ; to use current drive
  409.     cmp    byte ptr oldpath+1,drive_char    ; was it supplied?
  410.     jne    check1a         ; yes
  411.     mov    dl,byte ptr oldpath    ; drive supplied with oldpath
  412.     and    dl,5fh            ; insure upper case
  413.     mov    byte ptr olddrv,dl    ; and save
  414.     sub    dl,'A'-1                ; make into drive number
  415. check1a:
  416.     mov    ah,getdir        ; get current directory
  417.     mov    si,offset olddir    ;  for oldpath drive
  418.     int    idos            ;
  419.     mov    ah,chdir        ; change directory
  420.     mov    dx,offset oldpath    ;  to supplied oldpath name
  421.     int    idos            ;
  422.     jnc    check2            ; found it?
  423.     mov    dx,offset msg1        ; no, issue error message
  424.     jmp    sendmsg         ;  and exit
  425.  
  426. check2:
  427.     mov    ah,chdir        ; restore oldpath current directory
  428.     mov    dx,offset olddrv    ;  to original directory
  429.     int    idos            ;
  430.  
  431.     mov    dl,0            ; to use current drive
  432.     cmp    byte ptr newpath+1,drive_char    ; was it supplied?
  433.     jne    check2a         ; yes
  434.     mov    dl,byte ptr newpath    ; drive supplied with oldpath
  435.     and    dl,5fh            ; insure upper case
  436.     mov    byte ptr newdrv,dl    ; and save
  437.     sub    dl,'A'-1                ; make into drive number
  438. check2a:
  439.     mov    ah,getdir        ; get current directory
  440.     mov    si,offset newdir    ;  for newpath drive
  441.     int    idos            ;
  442.     mov    ah,chdir        ; change directory
  443.     mov    dx,offset newpath    ;   to new path name
  444.     int    idos            ;
  445.     jnc    checked         ; found it?
  446.     mov    dx,offset msg2        ; no, issue error message
  447.     jmp    sendmsg         ;  and exit
  448.  
  449. checked:                ; current directory is now newpath
  450.  
  451.     page
  452. ;
  453. ;    build list of files in master directory
  454.  
  455. build1:
  456.     mov    dl,byte ptr newdrv    ; reset current drive
  457.     sub    dl,'A'                  ;  to newpath drive
  458.     mov    ah,select        ; select disk
  459.     int    idos            ;
  460.  
  461.     mov    dx,offset cooking    ; show that we're working
  462.     mov    ah,pstrng
  463.     int    idos
  464.  
  465.     mov    di,offset table     ; first table spot
  466.     mov    dx,offset global    ; filespec for master directory
  467.     mov    cx,07h            ; file attributes: R+H+S
  468.     mov    ah,ffirst        ; find first matching file
  469.     int    idos
  470.     or    ax,ax
  471.     jz    build12         ; have first file?
  472.     mov    dx,offset errmsg1    ; oops, now what
  473.     jmp    sendmsg
  474.  
  475. build12:                ; add master file to the table
  476.     lea    si,dtawork.dtatime    ; point to good stuff
  477.     mov    cx,file_len        ; just this much and some more
  478.     rep    movsb
  479.     inc    count            ; and bump entry count
  480.     mov    ax,max            ; maximum table entries
  481.     cmp    count,ax        ;  exceeded?
  482.     jae    build2            ; yup, gotta go now
  483.     inc    mcount            ;
  484. build13:
  485.     mov    ah,fnext        ; find next matching file
  486.     int    idos
  487.     or    ax,ax            ; any more?
  488.     jz    build12         ; yes, add it into table
  489.  
  490.     page
  491. ;
  492. ;    build list of files in old directory
  493.  
  494. build2:
  495.     mov    old_table,di        ; save ptr to first oldpath entry
  496.  
  497.     mov    dl,byte ptr olddrv    ; get drive letter for oldpath
  498.     sub    dl,'A'                  ;  and convert to drive number
  499.     mov    ah,select        ; change current drive
  500.     int    idos            ;  to oldpath
  501.  
  502.     mov    dx,offset oldpath    ; change current directory
  503.     mov    ah,chdir        ;  to oldpath
  504.     int    idos            ;
  505.  
  506.     mov    dx,offset global    ; filespec for old directory search
  507.     mov    cx,07h            ; file attributes: R+H+S
  508.     mov    ah,ffirst        ; find first matching file
  509.     int    idos            ;
  510.     or    ax,ax            ; have first file?
  511.     jz    build22         ; yes, add to table
  512.     mov    dx,offset errmsg1    ; no, empty directory
  513.     jmp    sendmsg
  514.  
  515. build22:                ; add master file to the table
  516.     lea    si,dtawork.dtatime    ; point to good stuff
  517.     mov    cx,file_len        ; just this much and some more
  518.     rep    movsb            ;
  519.     inc    count            ; and bump entry count
  520.     mov    ax,max            ; maximum table entries
  521.     cmp    count,ax        ;  exceeded?
  522.     jae    find1            ; yup, gotta go now
  523.     inc    ocount            ;
  524. build23:
  525.     mov    ah,fnext        ; find next matching file
  526.     int    idos
  527.     or    ax,ax            ; any more?
  528.     jz    build22         ; yes, add it into table
  529.  
  530.     page
  531. ;
  532. ;    look for old/duplicate files now
  533.  
  534. find1:
  535.     mov    bx,offset table     ; first master entry
  536. find2:
  537.     mov    bp,old_table        ; first entry in old dir
  538.     mov    dx,ocount        ; these many in old dir
  539.  
  540. find2a:                 ; compare new/old asciiz file names
  541.     lea    di,filename[bp]     ; its filename part
  542.     lea    si,filename[bx]     ; point to a master dir entry
  543.     mov    cx,size filename    ; filename length
  544. find2b:
  545.     lodsb                ; file names match?
  546.     cmp    al,byte ptr [di]    ; match so far?
  547.     jne    find2d            ; no, try next oldpath entry
  548.     inc    di            ; yes, point to next char
  549.     cmp    al,0            ; end of asciiz name?
  550.     je    compare         ; yes, have match
  551.     loop    find2b            ;
  552.     jmp    compare         ; all matched
  553. find2d:
  554.     add    bp,file_len        ; point to next entry
  555.     sub    dx,1            ; no,
  556.     jnz    find2a            ;  any more to check?
  557.     jmp    skipit            ; not found
  558.  
  559.     page
  560. ;
  561. ;    compare old/new file dates, times and sizes
  562.  
  563. compare:
  564.     mov    si,bp            ; copy oldpath dta data
  565.     lea    di,dtawork.dtatime    ;  to work area
  566.     mov    cx,file_len        ;   for comparing
  567.     rep    movsb            ;    dta fields
  568.  
  569.     lea    si,dtawork.dtatime    ; compare file data
  570.     lea    di,word ptr filetime[bx] ; except for attribute byte
  571.     mov    cx,filename - filetime
  572.     repe    cmpsb
  573.     je    purge1            ; different, older or what?
  574.  
  575.     test    flags,newer        ; don't care about date/time/size?
  576.     jnz    purge1            ; right, delete matching file names
  577.  
  578.     test    flags,older        ; allowed to delete older files?
  579.     jnz    compare1        ; yes, check further
  580.     jmp    skipit            ; no, skip further checks
  581.  
  582. compare1:
  583.     mov    si,offset inform2    ; compare dates
  584.     mov    ax,word ptr dtawork.dtadate
  585.     cmp    ax,word ptr filedate.[bx]
  586.     jb    purge2            ; it's older file
  587.     je    compare2        ; it's the same
  588.     jmp    skipit            ; or newer
  589.  
  590. compare2:
  591.     mov    ax,word ptr dtawork.dtatime  ; compare times
  592.     cmp    ax,word ptr filetime.[bx]
  593.     jb    purge2            ; it's earlier
  594.     je    compare3        ; or the same
  595.     jmp    skipit            ; or later flavor
  596.  
  597. compare3:
  598.     mov    si,offset inform3    ; it same datestamp,
  599.     test    flags,similar        ;  but different size
  600.     jnz    purge2            ;   allowed to delete?
  601.     jmp    skipit            ; if /S not supplied
  602.  
  603.     page
  604. ;
  605. ;    print file information
  606.  
  607. purge1: mov    si,offset inform1    ; exact duplicate file
  608. purge2: mov    cx,7            ; copy reason to print line
  609.     mov    di,offset prtwhy    ;
  610.     rep    movsb            ;
  611.  
  612.     mov    cx,size filename    ; copy file name to print line
  613.     lea    si,dtawork.dtaname    ; point to file name
  614.     mov    di,offset prtname    ;  to copy here
  615. print1: lodsb                ; next filename char
  616.     cmp    al,zero         ; end of name?
  617.     je    print2            ; yes, ready
  618.     stosb                ; no, copy next char
  619.     loop    print1            ; continue
  620.     jcxz    print3            ; used entire name
  621. print2:
  622.     mov    al,blank        ; pad with spaces
  623.     rep    stosb
  624.  
  625. print3: inc    deleted         ; increment count of files processed
  626.     mov    dx,word ptr dtawork.dtasize+2
  627.     mov    ax,word ptr dtawork.dtasize
  628.     add    delsize+2,dx        ; add up total
  629.     add    delsize,ax        ;  deleted file
  630.     adc    delsize+2,0        ;   bytes
  631.  
  632.     mov    di,offset oldsize    ; format master file size
  633.     mov    dx,word ptr filesize+2[bx]
  634.     mov    ax,word ptr filesize[bx]
  635.     call    getsize
  636.  
  637.     mov    di,offset olddate    ; format date of master file
  638.     mov    ax,word ptr filedate[bx]
  639.     call    getdate
  640.  
  641.     mov    di,offset oldtime    ; format time of master file
  642.     mov    ax,word ptr filetime.[bx]
  643.     call    gettime         ;
  644.  
  645.     mov    prtstop,stopper     ; short print line if same
  646. ;;    cmp    word ptr prtwhy,'aS'    ; duplicate files?
  647. ;;    je    print4            ; yes, skip redundant info
  648.     mov    prtstop,blank        ; clear print line
  649.  
  650.     mov    di,offset newsize    ; format new file size
  651.     mov    dx,word ptr dtawork.dtasize+2
  652.     mov    ax,word ptr dtawork.dtasize
  653.     call    getsize
  654.  
  655.     mov    di,offset newdate    ; format date of new file
  656.     mov    ax,word ptr dtawork.dtadate
  657.     call    getdate
  658.  
  659.     mov    di,offset newtime    ; format time of new file
  660.     mov    ax,word ptr dtawork.dtatime
  661.     call    gettime
  662.  
  663. print4:
  664.     test    flags, pause        ; pause when screen fills?
  665.     jz    print5            ; no, just print
  666.     mov    ax,deleted        ; number of lines so far
  667.     mov    cl,byte ptr crtrows    ; max lines on screen
  668.     div    cl            ; get page number
  669.     or    ah,ah            ; at end of screen?
  670.     jnz    print5            ; no,
  671.     mov    dx,offset more        ; yes, prompt
  672.     mov    ah,pstrng        ; for operator action
  673.     int    idos            ;
  674.     mov    ah,dconio        ; wait for a key
  675.     int    idos            ;
  676.     and    flags,255-first     ; insure new headings
  677.  
  678. print5:
  679.     test    flags,first        ; first time to print?
  680.     jnz    print6            ; no, already have titles
  681.     mov    dx,offset titles    ; yes, show headings
  682.     call    prints            ;
  683.     or    flags,first        ; and indicate have titles
  684. print6:
  685.     mov    dx,offset prtline    ; print detail line
  686.     call    prints            ;
  687.  
  688.     test    flags, test        ; just display possible actions?
  689.     jnz    skipit            ; yes, don't really delete
  690.     page
  691. ;
  692. ;    delete the duplicate file
  693.  
  694.     test    flags, verify        ; want to confirm each delete?
  695.     jz    purge_now        ; no, just do it
  696.     and    flags,255-pause     ; /P is superfluous
  697.  
  698. askem:
  699.     mov    dx,offset prompt    ; display prompt message
  700.     mov    ah,pstrng        ; use print string function
  701.     int    idos            ;
  702.     mov    dx,offset reply     ; point to reply buffer
  703.     mov    ah,bufcon        ;  for buffered console i/o
  704.     int    idos            ;
  705.     mov    al,byte ptr answer    ; get their one char answer
  706.     and    al,5fh            ; make it upper case
  707.     cmp    al, 'Y'                 ; want to proceed?
  708.     je    purge_now        ;  yes
  709.     jmp    skipit            ;  no, let null enter skip it
  710.  
  711. purge_now:
  712.     lea    dx,dtawork.dtaname    ; point to file name
  713.     mov    ah,delete        ; delete a file
  714.     int    idos            ;
  715.     jc    skipit            ; oops, doesn't count
  716.  
  717. ;    bump to next table entry
  718.  
  719. skipit:
  720.     add    bx,file_len        ; point to next file entry
  721.     sub    mcount,one        ; any more?
  722.     jle    finished        ;
  723.     jmp    find2            ; yup, work work work
  724.  
  725. ;    finished processing all table entries
  726.  
  727. finished:
  728.     sub    dx,dx            ; get count
  729.     mov    ax,deleted        ;  of deleted files
  730.     mov    di,offset dcount    ;
  731.     call    getsize         ;
  732.     mov    dx,delsize+2        ; get total
  733.     mov    ax,delsize        ;  deleted file's
  734.     mov    di,offset dsize     ;   bytes
  735.     call    getsize         ;
  736.     mov    dx,offset donemsg    ; all done
  737.     cmp    deleted,zero        ; deleted any files?
  738.     ja    done            ; yes, looks good
  739.     mov    dx,offset errmsg2    ; no, say so
  740. done:
  741.     jmp    sendmsg         ; emit final blank line
  742.  
  743.     page
  744. ;
  745. ;    Format the date
  746. ;
  747. ; Input:    AX contains file date
  748. ;        DI points to area to fill in with formatted date
  749.  
  750. getdate proc    near            ; format the date
  751.     or    ax,ax            ; is it valid?
  752.     jz    gotdate         ; no, quit
  753.  
  754.     push    ax            ;Save it
  755.     and    ax,mask month        ;Get month part
  756.     mov    cl,month        ;Bits to shift
  757.     call    cnvrt
  758.     cmp    al,'0'                  ; Suppress leading zero
  759.     jne    getdat1
  760.     mov    al,' '
  761. getdat1:stosw
  762.     mov    al,'/'
  763.     stosb
  764.     pop    ax            ;Get the date back
  765.  
  766.     push    ax
  767.     and    ax,mask day        ;Get day part
  768.     mov    cl,day            ;Bits to shift
  769.     call    cnvrt
  770.     stosw
  771.     mov    al,'/'
  772.     stosb
  773.     pop    ax
  774.  
  775.     and    ax,mask year        ;Get year part
  776.     mov    cl,year         ;Bits to shift
  777.     call    cnvrt
  778.     or    al,'8'                  ;Adjust for base year
  779.     stosw
  780.  
  781. gotdate:
  782.     ret
  783. getdate endp
  784.  
  785. ;    Format the time
  786. ;
  787. ; Input:    AX contains file time
  788. ;        DI points to area to fill in with formatted time
  789.  
  790. gettime proc    near            ; format the date
  791.     or    ax,ax            ; is it valid?
  792.     jz    gottime
  793.     push    ax            ; save date
  794.     and    ax,mask hour        ; get hour part
  795.     mov    cl,hour         ; mask bits to shift
  796.     shr    ax,cl
  797.     call    cnvrt1
  798.     stosw
  799.     mov    al,':'
  800.     stosb
  801.     pop    ax            ; get the time back
  802.     and    ax,mask minute        ; get min part
  803.     mov    cl,minute        ; bits to shift
  804.     call    cnvrt
  805.     stosw
  806. gottime:
  807.     ret
  808. gettime endp
  809.  
  810. cnvrt    proc    near
  811.     shr    ax,cl
  812. cnvrt1: aam                ; make al into bcd
  813.     or    ax,'00'                 ;  and to ascii
  814.     xchg    al,ah
  815. cnvrtd: ret
  816. cnvrt    endp
  817.  
  818.     Page
  819. ;
  820. ;    Format double word
  821. ;
  822. ; Input:    DX:AX has binary value to format
  823. ;        DI points to area to fill with formatted ascii number
  824.  
  825. ddptr    Dw    0
  826.  
  827. getsize proc    near            ; formats a 32 bit integer
  828.     push    bp            ;  in dx:ax
  829.     push    bx            ;  to ds:si
  830.     push    di
  831.     push    si
  832.     mov    ddptr,di        ; addr of target field
  833.     mov    di,dx            ; routine uses di:si
  834.     mov    si,ax
  835.     call    printdw
  836.     pop    si
  837.     pop    di
  838.     pop    bx
  839.     pop    bp
  840.     ret
  841.  
  842. printdw:
  843.     xor    ax,ax            ; clear work regs
  844.     mov    bx,ax            ;
  845.     mov    bp,ax            ;
  846.     mov    cx,32            ; bits of precision
  847. j1:    shl    si,1
  848.     rcl    di,1
  849.     xchg    bp,ax
  850.     call    j6
  851.     xchg    bp,ax
  852.     xchg    bx,ax
  853.     call    j6
  854.     xchg    bx,ax
  855.     adc    al,0
  856.     loop    j1
  857.     mov    cx,1710h
  858.     mov    ax,bx
  859.     call    j2
  860.     mov    ax,bp
  861. j2:    push    ax
  862.     mov    dl,ah
  863.     call    j3
  864.     pop    dx
  865. j3:    mov    dh,dl
  866.     shr    dl,1            ; move high
  867.     shr    dl,1            ;  nibble to
  868.     shr    dl,1            ;   the low
  869.     shr    dl,1            ;    position
  870.     call    j4
  871.     mov    dl,dh
  872. j4:    and    dl,0fh            ; mask low nibble
  873.     jz    j5            ; if not zero
  874.     sub    cl,cl
  875. j5:    dec    ch
  876.     and    cl,ch
  877.     or    dl,'0'                  ; fold in ascii zero
  878.     sub    dl,cl
  879.     mov    bx,ddptr
  880.     mov    [bx],dl         ; ptr to next target field
  881.     inc    ddptr
  882.     ret
  883.  
  884. j6:    adc    al,al
  885.     daa
  886.     xchg    al,ah
  887.     adc    al,al
  888.     daa
  889.     xchg    al,ah
  890.     ret
  891. getsize endp
  892.  
  893.     page
  894. ;
  895. ;    Print string like int 21h function 9
  896.  
  897. prints    proc    near            ; dx has offset to string
  898.     push    di            ;  ending in char x'ff'
  899.     push    bx            ;
  900.     push    cx            ;
  901.     mov    di,dx            ; ptr to string text
  902.     mov    cx,-1            ; overall text length
  903.     mov    al,stopper        ; find ending hex ff
  904.     repne    scasb            ;
  905.     not    cx            ; length is bytes scanned
  906.     mov    bx,1            ; standard output device
  907.     mov    ah,write        ; write to a file or handle
  908.     int    idos            ;
  909.     pop    cx            ; recover registers
  910.     pop    bx            ;
  911.     pop    di            ;
  912.     ret                ;
  913. prints    endp
  914.  
  915.     page
  916. ;
  917. ;    dynamic work areas
  918.  
  919.     even
  920.  
  921. lstack    label    byte            ; local stack
  922.  
  923. table    equ    byte ptr lstack+256    ; contains master file entries
  924.                     ; as many as free memory will permit
  925.  
  926. pgmsize equ    table-cseg+256        ; program, psp and stack size
  927.  
  928. deldupe endp
  929.  
  930. cseg    ends
  931.  
  932.     end    deldupe
  933.