;- :ts=12 --------------------------------------------------------
;
;      rm -- remove files with Oops! possibility
;
;    /|||\               (c) Copyright 1989 by Martin J. Laubach
;   //|||\\                    All rights reserved
;  ///|||\\\
;
;-----------------------------------------------------------------

       ifd CAPE
       optimon
       addsym
       objfile "rm.o"
       endc

       include "exec/types.i"
       include "exec/alerts.i"
       include "exec/libraries.i"
       include "libraries/dos.i"
       include "arp/arpbase.i"

call   macro
       ifnd    _LVO\1
       xref    _LVO\1
       endc
       jsr     _LVO\1(a6)
       endm

       xref    _LVOAlert

ScratchSiz:    equ     256
JunkSiz:       equ     80

       section Remove,code

;---------------------------------------------------------------------------
; Try to open arp.library first. Write NoArp text if failure

main:  RESIDENT        3000

       movem.l a0/d0,-(a7)

       move.l  4,a6
       lea     ArpN(pc),a1
       moveq   #34,d0
       call    OpenLibrary
       tst.l   d0
       bne.s   ArpOK
       lea     DosN(pc),a1
       moveq   #34,d0
       call    OpenLibrary
       tst.l   d0
       bne.s   DosOK

;-------------------------------------
; Recoverable alert if no dos.library found

alertDos:      ALERT   (AG_OpenLib!AO_DOSLib)

EFail: moveq   #RETURN_FAIL,d0
       rts

;-------------------------------------
; Write OhAhNoArp text for user without arp.library
; Expects DOSBase in D0

DosOK: move.l  d0,a6
       call    Output
       move.l  d0,d1
       lea     NoArp(pc),a0
       move.l  a0,d2
       moveq   #NoArpEnd-NoArp,d3
       call    Write

       move.l  a6,a1
       move.l  4,a6
       call    CloseLibrary

       bra.s   EFail

;-------------------------------------
; Arp opened ok, now parse the command line
; Expects ArpBase in D0

ArpOK: move.l  d0,a6
       movem.l (a7)+,a0/d0

       lea     CLIHelp(pc),a1
       lea     -4(a7),a7
       move.l  a7,a2
       lea     CLITemp(pc),a3
       call    GADS
       move.l  (a7),a5
       lea     4(a7),a7

;-------------------------------------
; Check parameters, write usage if less than one
; Expects D0 number of paramaters

       tst.l   d0
       bne.s   ParamOK
       lea     Usage(pc),a1
       call    Puts
       bra.s   EFail

;--------------------------------------------------------------------------
; Parameters ok, begin to work on them
; D0: argument count
; A5: argument vector

ParamOK:       move.l  d0,d7

       lea     -JunkSiz(a7),a7
       move.l  a7,a2

       lea     Junk(pc),a0
       move.l  a2,a1
       moveq   #JunkSiz,d0
       call    Getenv

       tst.b   (a2)
       bne.s   NoEnv

       lea     Junk(pc),a2

NoEnv: subq.l  #1,d7

       moveq   #0,d5
       moveq   #0,d6

       lea     -ScratchSiz(a7),a7
       move.l  a7,a3
               
NextPar:       move.l  #SIGBREAKF_CTRL_C,d1
       sub.l   a1,a1
       call    CheckBreak
       tst.l   d0
       bne     BreakRcvd

       move.l  (a5)+,a4

;-------------------------------------
; Check if parameter contains | # ?
; Expects &parameter to check in A4, A3 scratch buffer

Chk4Pat:       move.l  a4,a1
;;;    moveq   #0,d1
1$:    move.b  (a1)+,d0
       beq.s   NoPattern
       cmp.b   #'?',d0
       beq.s   Pattern
       cmp.b   #'|',d0
       beq.s   Pattern
       cmp.b   #'#',d0
       bne.s   1$

;-------------------------------------
; Yes, must do pattern matching
; A4 supplied file name, A3 scratch buffer
; D6 return code, D5 return value

Pattern:       lea     -ap_SIZEOF-256(a7),a7

       move.l  #SIGBREAKF_CTRL_C,ap_BreakBits(a7)
       move.l  #256,ap_Length(a7)

       move.l  a4,d0
       move.l  a7,a0
       call    FindFirst
1$:    move.l  d0,d6
       bne.s   NoFiles

       tst.l   d5      
       bne.s   NoFiles

       lea     ap_SIZEOF(a7),a4
       bsr.s   Remove
;;;    tst.l   d0
       bne.s   2$
       moveq   #RETURN_FAIL,d5

2$:    move.l  a7,a0
       call    FindNext
       bra.s   1$

NoFiles:       tst.l   d6
       beq.s   1$
       cmp.w   #ERROR_NO_MORE_ENTRIES,d6
       beq.s   1$
       moveq   #RETURN_FAIL,d5

1$:    move.l  a7,a0
       call    FreeAnchorChain
       lea     ap_SIZEOF+256(a7),a7

       bra.s   EndLoop

;-------------------------------------
; No, normal remove will do
; A4 File name, A3 scratch buffer
; D5 return value

NoPattern:     bsr.s   Remove
;;;    tst.l   d0
       bne.s   EndLoop

       moveq   #RETURN_FAIL,d5
       move.l  #ERROR_OBJECT_NOT_FOUND,d6

EndLoop:       tst.l   d5
       dbne.s  d7,NextPar

       lea     ScratchSiz+JunkSiz(a7),a7

;-------------------------------------
; End this program

ExitOK:        moveq   #0,d2
       move.l  d5,d0
       beq.s   Exit
       move.l  d6,d2
Exit:  call    ArpExit
       rts

;-------------------------------------
; Break received -- print "***break" and exit program
; Expects pointer to break string in A1

BreakRcvd:     call    Puts
       bra.s   ExitOK
       move.l  #ERROR_BREAK,d2
ExitFail:      moveq   #RETURN_FAIL,d0
       bra.s   Exit


RmRet: moveq   #0,d0
       rts

;--------------------------------------------------------------------------
; Remove a file. 
; in: A4 = filename to be removed
;     A3 = 256 bytes scratch buffer area
;
; return 0 if failure, <>0 if remove succeeded

Remove:

;-------------------------------------
; Locate the complete file name
; Expects A4 filename, A3 scratch area

       move.l  a4,d1
       move.l  #ACCESS_READ,d2
       call    Lock

       move.l  d0,d3
       beq.s   Prnt
       move.l  a3,a0
       move.l  #256,d1
       call    PathName

       move.l  d3,d1
       call    UnLock

;-------------------------------------
; Print information
; Expects A3 full file name

Prnt:  tst.l   d3
       bne.s   1$

       move.l  a4,-(a7)
       lea     RemStr(pc),a0
       move.l  a7,a1
       call    Printf
       lea     4(a7),a7
       lea     Nofile(pc),a1
       call    Puts
       bra.s   RmRet

1$:    move.l  a3,-(a7)
       lea     RemStr(pc),a0
       move.l  a7,a1
       call    Printf
       lea     4(a7),a7
       
;-------------------------------------
; Isolate drive name
; Expects A3 full file name

Isolate:       move.l  a3,a0

1$:    move.b  (a0)+,d0
       cmp.b   #':',d0
       bne.s   1$
       clr.b   (a0)

;-------------------------------------
; Build path for rename
; Expects A2 "junk" dir name, A3 full file name, A4 original file name

       move.l  a3,a0
       move.l  a2,a1
       call    TackOn
       move.l  a4,a0
       call    BaseName
       move.l  d0,a1
       move.l  a3,a0
       call    TackOn

;-------------------------------------
; Munch file name so it is unique and doesn't exist
; Expects A3 full file name to move to

       moveq   #1,d4
FindEnd:       move.l  a3,a0
1$:    tst.b   (a0)+
       bne     1$
       lea     -1(a0),a0
       move.l  a0,d3
       
ChkEx: move.l  a3,d1
       move.l  #ACCESS_READ,d2
       call    Lock
       move.l  d0,d1
       beq.s   1$
       call    UnLock

       movem.l a2/a3/a6,-(a7)
       lea     FileFmt(pc),a0  ; Format string
       move.l  d4,-(a7)
       addq.l  #1,d4
       move.l  a7,a1           ; Output values
       move.l  d3,a3           ; Output buffer
       move.l  4,a6
       lea     StuffChar(pc),a2
       call    RawDoFmt
       lea     4(a7),a7
       movem.l (a7)+,a2/a3/a6

       bra.s   ChkEx

;-------------------------------------
; Now rename the file
; Expects A3 new, unique junk file name, A4 original file name

1$:    move.l  a4,d1
       move.l  a3,d2
Ren:   call    Rename
       move.l  d0,d3
       beq.s   1$
       lea     Success(pc),a1
       bra.s   2$
1$:    lea     Failed(pc),a1
2$:    call    Puts

       move.l  d3,d0
       rts

;-------------------------------------
; StuffChar, used for Sprintf style formatting

StuffChar:     move.b  d0,(a3)+
       rts

;-------------------------------------
;-------------------------------------

RemStr:        dc.b 'Removing %s...',0
FileFmt:       dc.b ';%ld',0
Success:       dc.b 'done',0
Failed:        dc.b 'failed',0
Nofile:        dc.b 'not found',0

Junk:  dc.b 'Junk',0
CLITemp:       dc.b 'FILES/'
Think: dc.b '...',0
CLIHelp:       dc.b 'Files to remove',0
Usage: dc.b 'Usage: rm <file> ...',0
DosN:  dc.b 'dos.library',0
ArpN:  ArpName
NoArp: dc.b 'You need arp.library V34+'
NoArpEnd:
TestByte:      dc.b $a

       end
