*****************************************************************
*                                                               *
*    Program Name: Update                                       *
*         Version: 1.0                                          *
*  Change History: 11-Nov-87 Initial Program Version            *
*                                                               *
*   Copyright (c) 1987 - Bob Rakosky                            *
*                                                               *
*   USAGE:                                                      *
*    Update [FROM] obj1 [obj2 ... obj12] TO dir [SINCE mfile]   *
*                                                               *
*    where obj1 ... obj12 are either files or directories,      *
*               (with or without wildcards)                     *
*          dir is the output directory name                     *
*          mfile is a file name                                 *
*                                                               *
*  Will copy all files specified (or in directories specified)  *
*  to dir IF the file's datestamp is later than the datestamp   *
*  for file mfile (if specified) or later than the datestamp    *
*  of the corresponding-named file in dir2 (if mfile not        *
*  specified).  In the latter case, if the corresponding file   *
*  does not exist in the output directory, the file is copied.  *
*                                                               *
*   NOTES                                                       *
*       This program REQUIRES the use of ARP.library, which     *
*       must be in your libs: logical directory.  If the        *
*       library is not present, the program will issue an error *
*       message and exit.                                       *
*                                                               *
*****************************************************************
        include "exec/types.i"
        include "exec/memory.i"
        include "libraries/dos.i"
        include "libraries/dosextens.i"
        include "arpbase.i"
*---------------------------------------------------------------*
*                   Some commonly used macros                   *
*---------------------------------------------------------------*

XTERN   MACRO           ;XTERN <reference> 
        XREF    _LVO\1  ; Adds the '_LVO' prefix to it.
        ENDM

CALL    MACRO           ;call < routine(register) >
        jsr     _LVO\1  ; Adds the '_LVO' prefix to the routine name.
        ENDM

*---------------------------------------------------------------*
*                             Equates                           *
*---------------------------------------------------------------*
Absbase EQU     4

*---------------------------------------------------------------*
*                       External references                     *
*---------------------------------------------------------------*
        XTERN   OpenLibrary
        XTERN   CloseLibrary
        XTERN   AllocMem
        XTERN   FreeMem
        XTERN   Output
        XTERN   Write
        XTERN   Read
        XTERN   Lock
        XTERN   UnLock
        XTERN   ParentDir
        XTERN   Examine
        XTERN   ExNext
        XTERN   Open
        XTERN   Close
        XTERN   IoErr
        XTERN   DeviceProc

*---------------------------------------------------------------*
*       Buffer Size for Read/Write Buffer                       *
*---------------------------------------------------------------*
RW_BUFS EQU     $4000           ;16 K Buffer size

*****************************************************************
*                          Main Program                         *
*****************************************************************

start   movem.l d1-d7/a0-a6,-(a7) ;save entry regs

        bsr     init            ;perform initialization
        tst.l   d0              ;Q. Good Return?
        bne     exit            ;A.  no - quit now

        bsr     parse           ;Parse the command line
        tst.l   d0              ;Q. Good return?
        bne     exit            ;A. No - exit

        tst.l   sinfil(a5)      ;Q. SINCE file name specified?
        beq.s   main010         ;A. no since file - bypass
        move.l  sinfil(a5),a0   ;address of SINCE file name
        bsr     getfib          ;get datestamp of file
        tst.l   d0              ;Q.  Good Return?
        beq.s   main010         ;A.  Yes - continue
*---------------------------------------------------------------*
*         Unable to locate/examine 'SINCE' file                 *
*---------------------------------------------------------------*
        lea     nosinm(pc),a0
        move.l  a0,d2           ;address message
        move.l  #nosinml,d3
        move.l  stdout(a5),d1
        move.l  dosaddr(a5),a6
*   Write(file,data,length)
*          d1   d2    d3
        CALL    Write(a6)
        moveq.l #20,d0          ;set bad return code
        bra     exit            ;and quit

main010:
        lea     fib(a5),a1      ;point to fib
        lea     fib_DateStamp(a1),a0  ;point to Datestamp
        lea     cmpdate(a5),a1  ;save 'since date' here
*---------------------------------------------------------------*
*       The datestamp for comparison will be one tick less      *
*       than that of the 'SINCE' file.                          *
*---------------------------------------------------------------*
        move.l  (a0)+,(a1)+     ;move datestamp days to compare area
        move.l  (a0)+,(a1)+     ;move datestamp minutes to compare area
        move.l  (a0),d0         ;get ticks
        subq.l  #1,d0           ;decrement by 1
        move.l  d0,(a1)         ;move ticks to compare area

*---------------------------------------------------------------*
*       Verify Output specified is a directory                  *
*---------------------------------------------------------------*
        move.l  todir(a5),a0    ;address of output directory name
        bsr     getfib          ;get file info
        tst.l   d0              ;Q.  Good Return?
        beq.s   main020         ;A.  Yes - continue
        move.l  stdout(a5),d1   ;msg file
        lea     noout(pc),a0
        move.l  a0,d2           ;address message
        move.l  #nooutl,d3      ;length of it.
        move.l  a4,a6           ;DOSBase into a6
*   Write(file,data,length)
*          d1   d2    d3
        CALL    Write(a6)       ;Send message to standard out
        moveq.l #20,d0          ;set return code
        bra.s   exit            ;and quit

main020:
        lea     fib(a5),a0      ;point to file info block
        move.l  fib_DirEntryType(a0),d0  ;file or directory indicator
        bpl.s   main030         ;> 0 ==> directory - continue
*---------------------------------------------------------------*
*       TO specified is not a directory                         *
*---------------------------------------------------------------*
        move.l  stdout(a5),d1   ;msg file
        lea     notdir(pc),a0
        move.l  a0,d2           ;address message
        move.l  #notdirl,d3     ;length of it.
        move.l  a4,a6           ;DOSBase into a6
*   Write(file,data,length)
*          d1   d2    d3
        CALL    Write(a6)       ;Send message to standard out
        moveq.l #20,d0          ;set return code
        bra.s   exit            ;and quit

main030:
*---------------------------------------------------------------*
*       copy target directory name to buffer and mark end       *
*---------------------------------------------------------------*
        move.l  todir(a5),a0    ;path name
        lea     outbuf(a5),a1   ;buffer area
1$:     move.b  (a0)+,(a1)+     ;next char
        bne     1$              ;loop until end of string 
        lea     -2(a1),a1       ;back up to last non-blank character
        move.b  (a1)+,d0        ;examine last character
        cmp.b   #':',d0         ;Q. Last character colon ?
        beq.s   2$              ;A. yes - don't append slash
        move.b  #'/',(a1)+      ;A. no - append a slash
2$:
        move.l  a1,outfnam(a5)  ;concat output file name here

*---------------------------------------------------------------*
*   loop and process all arguments                              *
*---------------------------------------------------------------*
        move.w  argc(a5),d7     ;number of arguments
        ext.l   d7
        move.l  #2,d6           ;reduce by at least 1 (for target)
                                ;  plus 1 to make relative to 0
        tst.l   sinfil(a5)      ;Q. Was 'since' option specified?
        beq.s   main040         ;A. No - bypass adjustment
        addq.l  #1,d6           ;A. Yes - one less input arguments
main040:
        sub.l   d6,d7           ;adjust loop counter
        clr.l   d6              ;index value into d6
        lea     argv(a5),a4     ;point to first arg
main050:
        move.l  0(a4,d6.w),a0   ;pick up next argument
        bsr     procarg         ;process input argument
        tst.l   d0              ;Q.  Good return?
        bne.s   exit            ;A.  No - quit now
        addq.w  #4,d6           ;increment index
        dbra    d7,main050      ;loop on
*---------------------------------------------------------------*
*   End of processing loop - set good return code and exit      *
*---------------------------------------------------------------*
        clr.l   d0              ;set good return code and exit
exit:   move.l  d0,-(a7)        ;save return code
        bsr     cleanup         ;free resources
        move.l  (a7)+,d0        ;restore return code
        movem.l (a7)+,d1-d7/a0-a6 ;restore other regs
        rts                     ;return to caller

        PAGE
*****************************************************************
*     Section Name: init                                        *
*         Function: Performs initial housekeeping               *
*  Entry Registers: a0 - command line string                    *
*                   d0 - command line length                    *
*   Exit Registers: d0 - return code (0 = success)              *
*                   a5 - work area address                      *
*****************************************************************

init:
        move.l  a0,a3           ;save command line
        move.l  d0,d3           ;  address and length
*---------------------------------------------------------------*
*                       Open DOS Library                        *
*---------------------------------------------------------------*
        move.l  Absbase,a6      ;find library
        lea     dosname(pc),a1  ;point to libname string
        moveq   #33,d0          ;version at least 1.2 (or higher)
*  libbase = OpenLibrary(libname,version);
*    d0                    a1      d0
        CALL    OpenLibrary(a6) ;open dos library
        movea.l d0,a4           ;save dos pointer for later use
        beq     init_err        ;OpenLibrary failed, can't tell user - just exit

*---------------------------------------------------------------*
*               Get Std Output File Handle                      *
*---------------------------------------------------------------*
        movea.l a4,a6           ;DosBase into a6
*   stdout = Output();
*     d0
        CALL    Output(a6)      ;get file handle for screen
        move.l  d0,d4           ;save filehandle

*---------------------------------------------------------------*
*                       Allocate work area                      *
*---------------------------------------------------------------*
        move.l  #wk_lgth,d0     ;length in d0
        move.l  #MEMF_CLEAR,d1  ;type in d1
        move.l  Absbase,a6
*   area = AllocMem(size,flags);
*    d0              d1   d0
        CALL    AllocMem(a6)    ;call AllocMem

        movea.l d0,a5           ;address work area 
        bne.s   init010        ;we now have a work area

*---------------------------------------------------------------*
*               Allocate failed - tell user and exit            *
*---------------------------------------------------------------*
        move.l  d4,d1           ;Std Output file handle
        beq.s   init_err        ;couldn't get screen handle - just exit

        lea     nomem(pc),a0
        move.l  a0,d2           ;address message
        move.l  #nomeml,d3      ;length of it.
        move.l  a4,a6           ;DOSBase into a6
*   Write(file,data,length)
*          d1   d2    d3
        CALL    Write(a6)       ;Send message to standard out
        bra.s   init_err        ;and leave

*---------------------------------------------------------------*
*               We now have a work area                         *
*---------------------------------------------------------------*
init010:
        move.l  a4,dosaddr(a5)  ;save dos address
        move.l  a3,cmdline(a5)  ;address of command line
        move.l  d3,cmdlen(a5)   ;length of command line
        move.l  d4,stdout(a5)   ;save address of Std Output

*---------------------------------------------------------------*
*               Open ARP Library                                *
*---------------------------------------------------------------*
        move.l  Absbase,a6      ;find library
        lea     arpname(pc),a1  ;point to libname string
        moveq   #ArpVersion,d0          ;version at least 1.2 (or higher)
*  libbase = OpenLibrary(libname,version);
*     d0                   a1       d0
        CALL    OpenLibrary(a6) ;open dos library
        move.l  d0,arpbase(a5)  ;save base pointer for later use
        bne     init020         ;OpenLibrary OK - initialization complete
*---------------------------------------------------------------*
*               Unable to open Arp Library                      *
*---------------------------------------------------------------*
        move.l  stdout(a5),d1   ;msg file
        lea     noarp(pc),a0
        move.l  a0,d2           ;address message
        move.l  #noarpl,d3      ;length of it.
        move.l  a4,a6           ;DOSBase into a6
*   Write(file,data,length);
*          d1   d2    d3
        CALL    Write(a6)       ;Send message to standard out
        bra.s   init_err        ;and leave

*---------------------------------------------------------------*
*               Initialization Complete                         *
*---------------------------------------------------------------*
init020:
        clr.l   d0              ;set good return code
        rts                     ;  return to sender

*---------------------------------------------------------------*
*               Initialization Error                            *
*---------------------------------------------------------------*
init_err:
        moveq.l #20,d0          ;set error return code
        rts

        PAGE
*****************************************************************
*     Section Name: parse                                       *
*         Function: Parse the command line                      *
*       Entry Data: cmdline - address of command line           *
*                   cmdlen - length of command line             *
*                         NOTE - relative to ZERO               *
*        Exit Data: d0 - return code (0 = success, 20 = error)  *
*                   argc - number of parameters specified       *
*                   argv - a table of pointers to the 'words'   *
*                                                               *
*****************************************************************

parse:
        movea.l cmdline(a5),a0  ;point to command line
        move.l  cmdlen(a5),d0   ;length of command line
        lea     cmdpr(pc),a1    ;help string
        lea     argv(a5),a2     ;arg array
        lea     templ(pc),a3    ;command template
        move.l  arpbase(a5),a6  ;arpbase
*  argc = GADS(cmdline,cmdlength,help,&argv[0],template);
*   d0           a0       d0      a1    a2        a3
        CALL    GADS(a6)        ;parse the command line
        move.w  d0,argc(a5)     ;store arg count
        ble.s   pars_err        ;==-1 -> parse error
                                ;==0 parsed ok but no arguments

*---------------------------------------------------------------*
*               Successful parse of command line                *
*---------------------------------------------------------------*
        clr.l   d0              ;good return code
        rts                     ;return

*---------------------------------------------------------------*
*  Unexpected error in parsing routine - should never happen    *
*---------------------------------------------------------------*

pars_err:
        lea     ferrm(pc),a0
        move.l  a0,d2           ;Set up and write err msg to console
        move.l  #ferrml,d3
        move.l  stdout(a5),d1
        move.l  dosaddr(a5),a6
*   Write(file,data,length);
*          d1   d2    d3
        CALL    Write(a6)
        moveq.l #20,d0          ;set bad return code
        rts                     ;and return

        PAGE
*****************************************************************
*     Section Name: cleanup                                     *
*                                                               *
*         Function: Frees all system resources acquired         *
*                                                               *
*       Entry Data: a5 - Address of global work area (if it     *
*                        exists                                 *
*                                                               *
*        Exit Data: none                                        *
*                                                               *
*****************************************************************

cleanup:
        move.l  a5,d0           ;address of work area
        beq.s   cleanret        ;  none - nothing to clean up
        move.l  databuf(a5),d0  ;Q. do we have a read/write buffer?
        beq.s   cln010          ;A.  NO - bypass freeing it
        move.l  d0,a1           ;address of area to free
        move.l  #RW_BUFS,d0     ;size of area to free
        move.l  Absbase,a6
*  FreeMem(area,size);
*           a1   d0
        CALL    FreeMem(a6)

cln010:
        move.l  arpbase(a5),d0  ;Q. Is ARP library open?
        beq.s   cln020          ;A. no - don't close it
        move.l  d0,a1           ;address of arp base
        move.l  Absbase,a6
*  CloseLibrary(libbase);
*                 d0
        CALL    CloseLibrary(a6)

cln020:
        move.l  a5,a1           ;address of work area
        move.l  #wk_lgth,d0     ;length of work area
        move.l  Absbase,a6      ;exec library
*  FreeMem(area,size);
*           a1   d0
        CALL    FreeMem(a6)     ;free work area
cleanret:
        rts                     ;return to caller

        PAGE
*****************************************************************
*     Section Name: procarg                                     *
*                                                               *
*         Function: Processes a single input argument from the  *
*                   command-line                                *
*                                                               *
*       Entry Data: a0 - pointer to argument, which is either   *
*                       a file or directory (with/without       *
*                       wild-cards                              *
*                                                               *
*        Exit Data: d0 - return code (0 = success)              *
*                                                               *
*****************************************************************

procarg:
        move.l  a0,-(a7)                ;push passed argument
        move.l  #128,d0
        lea     anchor(a5),a0           ;point to f/n search anchor
        move.l  d0,AP_LENGTH(a0)        ;length of fname
        move.l  (a7)+,d0                ;pop passed argument
        move.l  arpbase(a5),a6          ;ARP base
*  rc = FindFirst(pattern,chain)
*  d0               d0      a0
        CALL    FindFirst(a6)
        tst.l   d0                      ;Q.  Good Return?
        bne.s   parg_err                ;A.  No - error exit
parg010:
        lea     anchor(a5),a1           ;point to search anchor
        lea     AP_INFO(a1),a0          ;point to internal FIB
        move.l  fib_DirEntryType(a0),d0  ;file or directory indicator
        bpl     parg020                 ;> 0 ==> directory - continue
*---------------------------------------------------------------*
*       entry is a file                                         *
*---------------------------------------------------------------*
        lea     fname(a5),a1            ;point to full path name
                                        ;note - a0 still points to fib
        bsr     dofile                  ;process input file
        tst.l   d0                      ;Q. Good return?
        bne.s   parg_err                ;A. no - quit
        bra.s   parg030                 ;continue with next in chain

parg020:
*---------------------------------------------------------------*
*       entry is a directory                                    *
*---------------------------------------------------------------*
        bsr     dodir                   ;process input directory
        tst.l   d0                      ;Q. Good return?
        bne.s   parg_err                ;A. no - quit

parg030:
        lea     anchor(a5),a0           ;search anchor
        move.l  arpbase(a5),a6
*  rc = FindNext(chain)
*  d0              a0
        CALL    FindNext(a6)
        tst.l   d0
        beq.s   parg010                 ;loop on if next entry

*---------------------------------------------------------------*
*       End of chain - we are done with this argument           *
*---------------------------------------------------------------*
        lea     anchor(a5),a0           ;point to anchor
        move.l  arpbase(a5),a6          ;ARP base
*  FreeAnchorChain(chain)
*                    a0
        CALL    FreeAnchorChain(a6)

        clr.l   d0                      ;return code
        rts

parg_err:
        moveq.l #20,d0                  ;set error return code
        rts

        PAGE
*****************************************************************
*     Section Name: dodir                                       *
*                                                               *
*         Function: Processes a file directory included in the  *
*                   input argument list                         *
*                                                               *
*       Entry Data: fname(a5) contains the full path of the     *
*                       directory                               *
*                                                               *
*        Exit Data: d0 - return code (0 = success)              *
*                                                               *
*  NOTE:  This routine uses the AmigaDOS Examine/ExNext         *
*       functions, since wild cards are not needed              *
*                                                               *
*****************************************************************

dodir:
        movem.l d2-d3/a3-a4,-(a7)       ;save registers
        lea     dirbuf(a5),a0   ;buffer area to build file names
        lea     fname(a5),a1    ;path name of directory
1$:     move.b  (a1)+,(a0)+     ;move directory name to buffer
        bne.s   1$              ;stop at null

        lea     -2(a0),a0       ;point at last character
        move.b  (a0)+,d0        ;inspect last character
        cmp.b   #':',d0         ;Q. Is last character ':'?
        beq.s   ddir010         ;A. yes - don't append a /
        move.b  #'/',(a0)+      ;   no - append a / for path name
ddir010:
        move.l  a0,a4           ;save beginning address for file name
*---------------------------------------------------------------*
*       Allocate memory for local FIB                           *
*---------------------------------------------------------------*
        move.l  #fib_SIZEOF,d0  ;size of fib
        move.l  #MEMF_CLEAR,d1  ;allocation type
        move.l  Absbase,a6      ;Exec base
*  *ptr = AllocMem(size,type)
*   d0              d0   d1
        CALL    AllocMem(a6)    ;allocate fib
        tst.l   d0              ;Q.  Allocation successful?
        bne.s   ddir020         ;A.  yes - continue
*---------------------------------------------------------------*
*       Unable to allocate FIB - gotta quit                     *
*---------------------------------------------------------------*
        move.l  stdout(a5),d1           ;Std Output file handle
        lea     nomem(pc),a0
        move.l  a0,d2           ;address message
        move.l  #nomeml,d3      ;length of it.
        move.l  dosaddr(a5),a6          ;DOSBase into a6
*   Write(file,data,length)
*          d1   d2    d3
        CALL    Write(a6)       ;Send message to standard out
        bra     ddir_err        ;and leave

ddir020:
        move.l  d0,a3           ;save pointer to FIB
*---------------------------------------------------------------*
*               Obtain a lock on directory                      *
*---------------------------------------------------------------*
        lea     fname(a5),a0    ;point to directory name
        move.l  a0,d1
        move.l  #ACCESS_READ,d2 ;get a shared lock
        move.l  dosaddr(a5),a6
*  Lock = Lock(name,accessMode)
*   d0          d1      d2
        CALL    Lock(a6)
        tst.l   d0              ;Q.  Lock obtained?
        bne.s   ddir030         ;A.  yes - continue

        lea     fname(a5),a0
        move.l  a0,work(a5)     ;build argument list
        lea     work(a5),a1     ;point to argument list
        lea     dlokerr(pc),a0  ;printf pattern
        move.l  arpbase(a5),a6
*  Printf(string,*args)
*           a0     a1
        CALL    Printf(a6)
        bra     ddir_err        ;and leave

ddir030:
        move.l  d0,d3           ;save lock
*---------------------------------------------------------------*
*       Walk the directory chain, using Examine/ExNext          *
*---------------------------------------------------------------*
        move.l  d3,d1           ;lock
        move.l  a3,d2           ;pointer to fib
        move.l  dosaddr(a5),a6
*  success = Examine(lock,fib)
*     d0              d1   d2
        CALL    Examine(a6)
        tst.l   d0              ;Q. Successful?
        bne.s   ddir040         ;A. yes - continue

        lea     fname(a5),a0
        move.l  a0,work(a5)     ;build argument list
        lea     work(a5),a1     ;point to argument list
        lea     dexerr(pc),a0   ;printf pattern
        move.l  arpbase(a5),a6
*  Printf(string,*args)
*           a0     a1
        CALL    Printf(a6)
        bra     ddir_err        ;and leave

ddir040:
*---------------------------------------------------------------*
*       If entry is for a directory skip it                     *
* NOTE: The program will NOT recursively walk a nested          *
*       directory structure                                     *
*---------------------------------------------------------------*
        move.l  fib_DirEntryType(a3),d0 ;file or directory indicator
        bpl.s   ddir050         ; >= 0 ==> directory - bypass it
*---------------------------------------------------------------*
*       Entry is a file - build full file name                  *
*---------------------------------------------------------------*
        move.l  a4,a0           ;point to file path
        lea     fib_FileName(a3),a1  ;point to file name
1$:     move.b  (a1)+,(a0)+     ;append file name to path
        bne.s   1$              ;loop until null byte

*---------------------------------------------------------------*
*       Now process the file                                    *
*---------------------------------------------------------------*
        move.l  a3,a0           ;point to FIB
        lea     dirbuf(a5),a1   ;point to path name
        bsr     dofile          ;process file
        tst.l   d0              ;Q.  Success?
        beq.s   ddir050         ;A.  yes - continue
*---------------------------------------------------------------*
*       Error - free local resources and exit                   *
*---------------------------------------------------------------*
        move.l  a3,a1           ;address of fib
        move.l  #fib_SIZEOF,d0  ;length of fib
        move.l  Absbase,a6      ;exec library
*  FreeMem(area,size);
*           a1   d0
        CALL    FreeMem(a6)     ;free work area

        move.l  d3,d1           ;lock
        move.l  dosaddr(a5),a6
*  UnLock(lock)
*          d1
        CALL    UnLock(a6)      ;free lock
        bra.s   ddir_err

ddir050:
*---------------------------------------------------------------*
*               Get next entry in directory                     *
*---------------------------------------------------------------*
        move.l  d3,d1           ;lock
        move.l  a3,d2           ;pointer to FIB
        move.l  dosaddr(a5),a6
*  success = ExNext(lock,fib)
*     d0             d1   d2
        CALL    ExNext(a6)
        tst.l   d0              ;Q.  Success?
        bne.s   ddir040         ;A.  yes - loop on to process this entry
*---------------------------------------------------------------*
*       Insure that error is NO_MORE_ENTRIES                    *
*---------------------------------------------------------------*
        move.l  dosaddr(a5),a6
*  error = IoErr()
*   d0
        CALL    IoErr(a6)       ;get DOS error code
        move.l  d0,-(a7)        ;save error code on stack
*---------------------------------------------------------------*
*               Free Resources                                  *
*---------------------------------------------------------------*
        move.l  a3,a1           ;address of fib
        move.l  #fib_SIZEOF,d0  ;length of fib
        move.l  Absbase,a6      ;exec library
*  FreeMem(area,size);
*           a1   d0
        CALL    FreeMem(a6)     ;free work area

        move.l  d3,d1           ;lock
        move.l  dosaddr(a5),a6
*  UnLock(lock)
*          d1
        CALL    UnLock(a6)      ;free lock

        move.l  (a7)+,d0        ;pop DOS error code
        cmp.l   #ERROR_NO_MORE_ENTRIES,d0  ;Q.  Expected 'error' value?
        beq.s   ddir060         ;yes - ok to return
        move.l  d0,work(a5)     ;no - put error code in arg list
        lea     work(a5),a1     ;point to arg list
        lea     baddir(pc),a0   ;Printf pattern
        move.l  arpbase(a5),a6
*  Printf(string,*args)
*           a0     a1
        CALL    Printf(a6)      ;print error message
        bra.s   ddir_err        ;take error exit

ddir060:
        movem.l (a7)+,d2-d3/a3-a4       ;restore registers
        clr.l   d0              ;good return code
        rts

ddir_err:
        movem.l (a7)+,d2-d3/a3-a4       ;restore registers
        moveq.l #20,d0          ;error return code
        rts

        PAGE
*****************************************************************
*     Section Name: dofile                                      *
*                                                               *
*         Function: Processes a file included in the input      *
*                   argument list                               *
*                                                               *
*       Entry Data: a0 - FIB for file                           *
*                   a1 - full path name for file                *
*                                                               *
*        Exit Data: d0 - return code (0 = success)              *
*                                                               *
*****************************************************************

dofile:
        movem.l d2-d5/a2-a4,-(a7)       ;save registers
        move.l  a0,a3           ;save FIB pointer
        move.l  a1,a4           ;save name pointer
*---------------------------------------------------------------*
*       Construct full path name for output file                *
*---------------------------------------------------------------*
        lea     fib_FileName(a0),a1     ;point to file name of input
        move.l  outfnam(a5),a0  ;point into buffer containing output path
1$:     move.b  (a1)+,(a0)+     ;append file name to path
        bne.s   1$              ;loop until null-byte

*---------------------------------------------------------------*
*               Get date for comparison                         *
*---------------------------------------------------------------*
        bsr     getcdate        ;get datestamp for compare
        tst.l   d0              ;Q.  Good return?
        bne     dofl_err        ;A.  No - quit now

        lea     cmpdate(a5),a0  ;point to compare date stamp
        lea     fib_DateStamp(a3),a1 ;point to FIB date stamp
        moveq.l #2,d0           ;loop count - 3 long words
dofl010:
        move.l  (a0)+,d1        ;next long word from compare date
        cmp.l   (a1)+,d1        ;compare to next long word from FIB
        blt.s   dofl020         ;branch if FIB datestamp is higher
        bgt     dofl090         ;if FIB datestamp lower - do not process
        dbra    d0,dofl010      ;check entire DateStamp
        bra     dofl090         ;FIB date is equal to - skip file

dofl020:
*---------------------------------------------------------------*
*  File is to be processed - tell user                          *
*---------------------------------------------------------------*
        move.l  a4,work(a5)     ;build argument list
        lea     work(a5),a1     ;point to argument list
        lea     fline(pc),a0    ;printf pattern
        move.l  arpbase(a5),a6
*  Printf(string,*args)
*           a0     a1
        CALL    Printf(a6)
*---------------------------------------------------------------*
*       Open Input file                                         *
*---------------------------------------------------------------*
        move.l  a4,d1           ;pointer to file name
        move.l  #MODE_OLDFILE,d2        ;access mode
        move.l  dosaddr(a5),a6
*  file = Open(name,accessMode)
*   d0          d1      d2
        CALL    Open(a6)        ;Open input file
        tst.l   d0              ;Q. open successful?
        bne.s   dofl030         ;A. yes - continue
*---------------------------------------------------------------*
*       Input file failed to open - inform user and exit        *
*---------------------------------------------------------------*
        lea     iopnerm(pc),a0
        move.l  a0,d2           ;Set up and write err msg to console
        move.l  #iopnerl,d3
        move.l  stdout(a5),d1
        move.l  dosaddr(a5),a6
*   Write(file,data,size)
*          d1   d2   d3
        CALL    Write(a6)
        bra     dofl_err

dofl030:
        move.l  d0,d4           ;save input file handle
*---------------------------------------------------------------*
*               Open output file                                *
*---------------------------------------------------------------*
        lea     outbuf(a5),a0   ;point to output file path/name
        move.l  a0,d1           ;pointer to file name
        move.l  #MODE_NEWFILE,d2        ;access mode
        move.l  dosaddr(a5),a6
*  file = Open(name,accessMode)
*   d0          d1      d2
        CALL    Open(a6)        ;Open output file
        tst.l   d0              ;Q. open successful?
        bne.s   dofl040         ;A. yes - continue
*---------------------------------------------------------------*
*       Output file failed to open - inform user and exit       *
*---------------------------------------------------------------*
        lea     oopnerm(pc),a0
        move.l  a0,d2           ;Set up and write err msg to console
        move.l  #oopnerl,d3
        move.l  stdout(a5),d1
        move.l  dosaddr(a5),a6
*   Write(file,data,size)
*          d1   d2   d3
        CALL    Write(a6)
        move.l  d4,d1           ;Close Input file
        move.l  dosaddr(a5),a6
*   Close(file)
*          d1
        CALL    Close(a6)
        bra.s   dofl_err

dofl040:
        move.l  d0,d5           ;save output file handle
        move.l  d4,d1           ;input file handle in d1
        bsr     copyfile        ;copy the files
        move.l  d0,-(a7)        ;save copy return code

*---------------------------------------------------------------*
*       Close the files                                         *
*---------------------------------------------------------------*
        move.l  d5,d1           ;Output file handle
        move.l  dosaddr(a5),a6
*  Close(file)
*         d1
        CALL    Close(a6)       ;close output file
        move.l  d4,d1           ;Input file handle
        move.l  dosaddr(a5),a6
*  Close(file)
*         d1
        CALL    Close(a6)       ;close input file

        move.l  (a7)+,d0        ;restore return code from copy
        tst.l   d0              ;Q. Good return from copy?
        bne.s   dofl_err        ;A. no - quit
*---------------------------------------------------------------*
*       Set DateStamp of output file to match input             *
*---------------------------------------------------------------*
        move.l  a3,a0           ;FIB of input file
        bsr     setdate         ;call set date routine

        lea     foklin(pc),a0
        move.l  a0,d2           ;Set up and write ok msg to console
        move.l  #foklinl,d3
        move.l  stdout(a5),d1
        move.l  dosaddr(a5),a6
*   Write(file,data,length)
*          d1   d2    d3
        CALL    Write(a6)

dofl090:
        clr.l   d0
        movem.l (a7)+,d2-d5/a2-a4       ;restore registers
        rts

dofl_err:
        moveq.l #20,d0                  ;set error return code
        movem.l (a7)+,d2-d5/a2-a4       ;restore registers
        rts

        PAGE
*****************************************************************
*     Section Name: getcdate                                    *
*                                                               *
*         Function: Obtains the datestamp of the corresponding  *
*                   output file (if since option not used)      *
*                                                               *
*       Entry Data: outbuf(a5) contains full path name of       *
*                       output file                             *
*                                                               *
*        Exit Data: cmpdate(a5) will contain the date for       *
*                       comparison                              *
*                   d0 - return code (0 = success)              *
*                                                               *
*       NOTE:   if 'since' option was specified, this routine   *
*               will just return.  The cmpdate field has already*
*               been populated with the correct date            *
*                                                               *
*****************************************************************

getcdate:
        tst.l   sinfil(a5)      ;Q. SINCE file specified?
        beq.s   gcdt010         ;A. No - proceed
        clr.l   d0              ;A. yes - set good return code
        rts                     ;       and return
gcdt010:
        movem.l d2-d4,-(a7)     ;save work registers
*---------------------------------------------------------------*
*  Obtain a lock on the output file - if file does not exist    *
*  this will fail.  In this case, set cmpdate to zeros so the   *
*  comparison will result in the file being processed           *
*---------------------------------------------------------------*
        lea     outbuf(a5),a0   ;point to output file path/name
        move.l  a0,d1
        move.l  #ACCESS_READ,d2 ;get a shared lock
        move.l  dosaddr(a5),a6
*  Lock = Lock(name,accessMode)
*   d0          d1      d2
        CALL    Lock(a6)
        tst.l   d0              ;Q.  Lock obtained?
        bne.s   gcdt020         ;A.  yes - continue
        lea     cmpdate(a5),a0  ;A.  no - point to compare date
        moveq.l #2,d0           ;loop control - set 3 longwords to 0
1$:     clr.l   (a0)+           ;set datestamp to 0's
        dbra    d0,1$           ;   for 3 long words
        movem.l (a7)+,d2-d4     ;restore registers
        clr.l   d0              ;set good return code
        rts                     ;and return

gcdt020:
*---------------------------------------------------------------*
*               Now get File Info for file                      *
*---------------------------------------------------------------*
        move.l  d0,d4           ;save Lock
        move.l  d0,d1           ;lock in d1
        lea     fib(a5),a0      ;point to work fib
        move.l  a0,d2           ;FIB pointer in d2
        move.l  dosaddr(a5),a6
*    success = Examine(lock,FIB)
*      d0               d1   d2
        CALL    Examine(a6)
        move.l  d0,-(a7)        ;save Examine return code on stack
*---------------------------------------------------------------*
*       Free the lock obtained above                            *
*---------------------------------------------------------------*
        move.l  d4,d1           ;lock into d1
        move.l  dosaddr(a5),a6
*   UnLock(lock)
*           d1
        CALL    UnLock(a6)      ;free the lock

        move.l  (a7)+,d0        ;restore Examine return code from stack
        tst.l   d0              ;Q.  Success?
        beq     gcdt_err        ;A.  No - examine failed

        lea     fib(a5),a0      ;point to fib
        lea     fib_DateStamp(a0),a1    ;point to file's datestamp
        lea     cmpdate(a5),a0  ;point to comparison datestamp
        moveq.l #2,d0           ;loop control - move 3 long words
1$:     move.l  (a1)+,(a0)+     ;move file's datestamp to compare field
        dbra    d0,1$           ;  move all 3 long words

        movem.l (a7)+,d2-d4     ;restore registers
        clr.l   d0              ;good return code
        rts                     ;  return to caller

gcdt_err:
        lea     exerm(pc),a0
        move.l  a0,d2           ;Set up and write err msg to console
        move.l  #exerl,d3
        move.l  stdout(a5),d1
        move.l  dosaddr(a5),a6
*   Write(file,data,length)
*          d1   d2    d3
        CALL    Write(a6)
        movem.l (a7)+,d2-d4     ;restore registers
        moveq.l #20,d0          ;set bad return code
        rts                     ;and return

        PAGE
*****************************************************************
*     Section Name: copyfile                                    *
*                                                               *
*         Function: Copies input file to output file            *
*                                                               *
*       Entry Data: d0 - file handle for (opened) output file   *
*                   d1 - file handle for (opened) input file    *
*                                                               *
*        Exit Data: d0 - return code (0 = success)              *
*                                                               *
*****************************************************************

copyfile:
        movem.l d3-d6/a2-a4,-(a7)       ;save registers
        move.l  d0,d4                   ;save output file handle
        move.l  d1,d5                   ;save input file handle 
        move.l  databuf(a5),d0          ;address of data buffer
        bne.s   cpfl010                 ;bypass alloc if buffer exists
*---------------------------------------------------------------*
*       Allocate work buffer for reading/writing                *
*---------------------------------------------------------------*
        move.l  #RW_BUFS,d0     ;size of buffer
        move.l  #MEMF_CLEAR,d1  ;allocation type
        move.l  Absbase,a6      ;Exec base
*  *ptr = AllocMem(size,type)
*   d0              d0   d1
        CALL    AllocMem(a6)    ;allocate buffer
        move.l  d0,databuf(a5)  ;save and test address
        bne     cpfl010         ;continue if alloc successful
*---------------------------------------------------------------*
*       Unable to allocate buffer - gotta quit                  *
*---------------------------------------------------------------*
        move.l  stdout(a5),d1           ;Std Output file handle
        lea     nomem(pc),a0
        move.l  a0,d2           ;address message
        move.l  #nomeml,d3      ;length of it.
        move.l  dosaddr(a5),a6          ;DOSBase into a6
*   Write(file,data,length)
*          d1   d2    d3
        CALL    Write(a6)       ;Send message to standard out
        bra     cpfl_err        ;and leave

cpfl010:
*---------------------------------------------------------------*
*               Read input file                                 *
*---------------------------------------------------------------*
        move.l  d5,d1           ;input file handle
        move.l  databuf(a5),d2  ;address of buffer
        move.l  #RW_BUFS,d3     ;max length to read
        move.l  dosaddr(a5),a6
*  actualLength = Read(file,buffer,maxLength)
*      d0               d1   d2      d3
        CALL    Read(a6)
        move.l  d0,d6           ;save actual length read
        beq     cpfl090         ;0 ==> end-of-file
        bpl.s   cpfl020         ; > 0 data read OK
*---------------------------------------------------------------*
*       A Read error has occured                                *
*---------------------------------------------------------------*
        move.l  dosaddr(a5),a6
*  error = IoErr()
*    d0
        CALL    IoErr(a6)       ;get actual error value
        move.l  d0,work(a5)     ;store in parm list for Printf
        lea     rderrm(pc),a0   ;string pattern
        lea     work(a5),a1     ;arg array
        move.l  arpbase(a5),a6
*  count = Printf(*string,*arg-array)
*   d0               a0      a1
        CALL    Printf(a6)      ;write error message
        bra.s   cpfl_err        ;take error exit

cpfl020:
*---------------------------------------------------------------*
*       Write same data to output file                          *
*---------------------------------------------------------------*
        move.l  d4,d1           ;output file handle
        move.l  databuf(a5),d2  ;buffer address
        move.l  d6,d3           ;length of data read
        move.l  dosaddr(a5),a6
*  returnedLength = Write(file,buffer,length);
*      d0                  d1   d2      d3
        CALL    Write(a6)       ;write data to output file
        cmp.l   d0,d6           ;Q. did we write all the data?
        beq.s   cpfl010         ;A. YES - loop on for rest of data

*---------------------------------------------------------------*
*   An error occurred writing, since not all data was written   *
*---------------------------------------------------------------*
        move.l  dosaddr(a5),a6
*  error = IoErr()
*    d0
        CALL    IoErr(a6)       ;get actual error value
        move.l  d0,work(a5)     ;store in parm list for Printf
        lea     wrerrm(pc),a0   ;string pattern
        lea     work(a5),a1     ;arg array
        move.l  arpbase(a5),a6
*  count = Printf(*string,*arg-array)
*    d0             a0       a1
        CALL    Printf(a6)      ;write error message

cpfl_err:
        movem.l (a7)+,d3-d6/a2-a4       ;restore registers
        moveq.l #20,d0          ;error return code
        rts                     ;return to caller

cpfl090:
        movem.l (a7)+,d3-d6/a2-a4       ;restore registers
        clr.l   d0              ;good return code
        rts                     ;return

        PAGE
*****************************************************************
*     Section Name: getfib                                      *
*                                                               *
*         Function: Gets the FileInfoBlock for the passed       *
*                   named file                                  *
*                                                               *
*       Entry Data: a5 - Address of global work area            *
*                   a0 - address of file name string            *
*                                                               *
*        Exit Data: d0 - return code (0 = success)              *
*                   fib(a5) - filled in File Info block         *
*                                                               *
*****************************************************************

getfib:
        movem.l d2/d3,-(a7) ;save registers
*---------------------------------------------------------------*
*         Get a shared lock on the file                         *
*---------------------------------------------------------------*
        move.l  a0,d1           ;file name in d1
        move.l  #ACCESS_READ,d2 ;lock type
        move.l  dosaddr(a5),a6  ;DOSBase
*  lock = Lock(name,mode)
*   d0          d1   d2
        CALL    Lock(a6)
        tst.l   d0              ;Q.  Lock obtained?
        beq.s   gfib_err        ;A.  No - return error

        move.l  d0,d3           ;save lock
*---------------------------------------------------------------*
*               now get File Info from lock                     *
*---------------------------------------------------------------*
        move.l  d3,d1           ;lock in d1
        lea     fib(a5),a0      ;address fib
        move.l  a0,d2           ;FIB address in d2
        move.l  dosaddr(a5),a6
*  boolean = Examine(lock,&FileInfoBlock);
*    d0               d1       d2
        CALL    Examine(a6)
        move.l  d0,-(a7)        ;save Examine return code
*---------------------------------------------------------------*
*       Free Lock (we are done with it)                         *
*---------------------------------------------------------------*
        move.l  d3,d1           ;lock in d1
        move.l  dosaddr(a5),a6
*  UnLock(lock);
*          d1
        CALL    UnLock(a6)      ;free lock

        move.l  (a7)+,d0        ;restore return code from examine
        tst.l   d0              ;Q.  Good return from Examine?
        beq.s   gfib_err        ;A.  no - take error exit

*---------------------------------------------------------------*
*               Successful processing                           *
*---------------------------------------------------------------*
        clr.l   d0              ;set good return code
        movem.l (a7)+,d2/d3     ;restore registers
        rts                     ;and return

*---------------------------------------------------------------*
*               Error exit                                      *
*---------------------------------------------------------------*
gfib_err:
        moveq.l #20,d0          ;set bad return code
        movem.l (a7)+,d2/d3     ;restore registers
        rts                     ;and return

        PAGE
*****************************************************************
*     Section Name: setdate                                     *
*                                                               *
*         Function: Sets the datestamp for the output file      *
*                   to match that contained in the input FIB    *
*                                                               *
*       Entry Data: outbuf(a5) contains full path name of       *
*                       output file                             *
*                   a0 - the address of the input file's FIB    *
*                                                               *
*        Exit Data: N/A (Note: errors are considered non-       *
*                   critical and are ignored)                   *
*****************************************************************

setdate:
        movem.l d3/d4/a3/a4,-(a7)       ;save registers
        move.l  a0,a3           ;save address of fib
*---------------------------------------------------------------*
*       Get Handler Process address                             *
*---------------------------------------------------------------*
        lea     outbuf(a5),a0   ;get output file name
        move.l  a0,d1
        move.l  dosaddr(a5),a6
*  process - DeviceProc(name)
*     d0                 d1
        CALL    DeviceProc(a6)
        tst.l   d0              ;Q. Handler found?
        beq.s   sdat090         ;A.  no - can't continue
        move.l  d0,a4           ;    yes - save handler address

*---------------------------------------------------------------*
*       Get a lock on the output file                           *
*---------------------------------------------------------------*
        lea     outbuf(a5),a0   ;name of output file
        move.l  a0,d1
        move.l  #ACCESS_READ,d2 ;lock type (shared)
        move.l  dosaddr(a5),a6
*  lock = Lock(name,accessMode)
*   d0          d1     d2
        CALL    Lock(a6)
        tst.l   d0              ;Q. Lock obtained?
        beq.s   sdat090         ;A. No - cannot continue
        move.l  d0,-(a7)        ;   yes - save lock on stack
*---------------------------------------------------------------*
*               Get lock for parent directory                   *
*---------------------------------------------------------------*
        move.l  d0,d1           ;lock into d1
*  lock = ParentDir(lock)
*   d0               d1
        CALL    ParentDir(a6)
        move.l  d0,d3           ;save lock (note: this CAN be zero)
*---------------------------------------------------------------*
*  Free the first lock we obtained - don't need it any more     *
*---------------------------------------------------------------*
        move.l  (a7)+,d1        ;lock for output file
*  UnLock(lock)
*          d1
        CALL    UnLock(a6)      ;free this lock
*---------------------------------------------------------------*
*  Now build the file name as a BCPL string                     *
*       NOTE: this name MUST NOT include any path information,  *
*             just the file name                                *
*---------------------------------------------------------------*
        lea     strwork+1(a5),a0        ;string work area (saving the 1st byte)
        lea     fib_FileName(a3),a1     ;file name in passed FIB
        clr.l   d0                      ;set count to 0
1$:     addq.b  #1,d0           ;increment count
        move.b  (a1)+,(a0)+     ;move byte
        bne.s   1$              ;loop until null byte
        subq.b  #1,d0           ;don't count null byte
        move.b  d0,strwork(a5)  ;length into first byte
*---------------------------------------------------------------*
*       Build Argument list for DOS Packet                      *
*---------------------------------------------------------------*
        clr.l   pktarg0(a5)     ;first argument null
        move.l  d3,pktarg1(a5)  ;second argument is lock of parent dir
        lea     strwork(a5),a0  ;pointer to BSTR file name
        move.l  a0,d0
        lsr.l   #2,d0           ;convert to BCPL pointer (BPTR)
        move.l  d0,pktarg2(a5)  ;third argument is BSTR pointer to file name
        lea     fib_DateStamp(a3),a0
        move.l  a0,pktarg3(a5)  ;fourth arg is REAL pointer to DateStamp
*---------------------------------------------------------------*
*   Now use the ARP routine to send the DOS Packet              *
*---------------------------------------------------------------*
        move.l  #ACTION_SET_DATE,d0
        lea     pktarg0(a5),a0
        move.l  a4,a1           ;handler process
        move.l  arpbase(a5),a6
*  Result1 = SendPacket(action, args, handler)
*    d0                   d0     a0     a1
        CALL    SendPacket(a6)
*---------------------------------------------------------------*
* ignore return code - if it worked, it worked - if not, not    *
*                                                               *
*       Free the lock on the Parent Directory                   *
*---------------------------------------------------------------*
        move.l  d3,d1
        move.l  dosaddr(a5),a6
*  UnLock(lock)
*          d1
        CALL    UnLock(a6)

sdat090:
        movem.l (a7)+,d3/d4/a3/a4       ;restore registers
        rts

        PAGE
*---------------------------------------------------------------*
*                    Program Constants                          *
*---------------------------------------------------------------*

dosname dc.b    'dos.library',0
arpname dc.b    'arp.library',0

        CNOP    0,4
nomem   dc.b    'Unable to allocate work area - aborted',$0a
nomeml  EQU     *-nomem

noarp   dc.b    'Unable to Open ARP Library - aborted',$0a
noarpl  EQU     *-noarp

nosinm  dc.b    'Unable to locate SINCE file - aborted',$0a
nosinml EQU     *-nosinm

noout   dc.b    'Unable to locate TO directory - aborted',$0a
nooutl  EQU     *-noout

notdir  dc.b    'Specified TO parameter is not a directory - aborted',$0a
notdirl EQU     *-notdir

templ   dc.b    'FROM/A,,,,,,,,,,,,TO/A/K,SINCE/K',0

cmdpr   dc.b    'Usage:  ',$9b,'1;32mUpdate',$9b,'0;31m [FROM] ',$9b,'1;32mobj1 '
        dc.b    $9b,'0;31m[obj2 ... obj12] ',$9b,'1;32mTO dir',$9b
        dc.b    '0;31m [SINCE mfile]',$0a,$0a
        dc.b    '   Where ',$9b,'1mobj1...obj12',$9b,'0m are either files '
        dc.b    'or directories (with or without',$0a
        dc.b    '             wildcards, specifying input files to be checked'
        dc.b    $0a,$0a
        dc.b    '         ',$9b,'1mdir',$9b,'0m is the output directory '
        dc.b    'to receive the qualifying files',$0a,$0a
        dc.b    '    and  ',$9b,'1mmfile',$9b,'0m specifies the '
        dc.b    'optional file whose datestamp will be ',$0a
        dc.b    '             used to determine which input files '
        dc.b    'will updated in the ',$0a
        dc.b    '             output directory - NOTE that if no SINCE '
        dc.b    'file is specified,',$0a
        dc.b    '             the corresponding file in the TO directory '
        dc.b    'will be checked',$0a,0

ferrm   dc.b    'Command format error',$0a
ferrml  EQU     *-ferrm

fline   dc.b    '... %s ',0
foklin  dc.b    '  copied',$0a
foklinl EQU     *-foklin
iopnerm dc.b    '  Unable to Open Input file - Aborted',$0a
iopnerl EQU     *-iopnerm
oopnerm dc.b    '  Unable to Open Output file - Aborted',$0a
oopnerl EQU     *-oopnerm
exerm   dc.b    '  Error examining output file after locking - Aborted',$0a
exerl   EQU     *-exerm
rderrm  dc.b    ' Read Error - code %ld',$0a,0
wrerrm  dc.b    ' Write Error - code %ld',$0a,0
dlokerr dc.b    '  Unable to Lock Input directory %s - Aborted',$0a,0
dexerr  dc.b    '  Unable to Examine Input directory %s - Aborted',$0a,0
baddir  dc.b    '  Corrupted Directory chain - error %ld - Aborted',$0a,0

        CNOP    0,4
        PAGE
*---------------------------------------------------------------*
*                          Work Area                            *
* Note: the following areas are actually obtained by an Alloc-  *
*       Mem system call, and addressed relative to register a5  *
*---------------------------------------------------------------*
        OFFSET  0
cmdline ds.l    1               ;pointer to command line
cmdlen  ds.l    1               ;length of command line
dosaddr ds.l    1               ;address of DOSBase
arpbase ds.l    1               ;address of ArpBase
stdout  ds.l    1               ;file handle of std output
databuf ds.l    1               ;pointer to 16K data buffer for copying files
argv    ds.l    12              ;argument vectors for input names (FROM)
todir   ds.l    1               ;arg vector for TO keyword
sinfil  ds.l    1               ;arg vector for SINCE file
cmpdate ds.l    3               ;DateStamp for compare
work    ds.l    1               ;work word (for printf)
outfnam ds.l    1               ;pointer into outbuf for file name
pktargs ds.l    7               ;arg array for DOS Packets
pktarg0 EQU     pktargs
pktarg1 EQU     pktargs+4
pktarg2 EQU     pktargs+8
pktarg3 EQU     pktargs+12
argc    ds.w    1               ;argument count (max 64)

        CNOP    0,4
fib     ds.b    fib_SIZEOF      ;work FileInfoBlock
        CNOP    0,4
anchor  ds.b    AP_SIZEOF       ;arp w/c file search anchor
fname   ds.b    128             ;buffer for arp to build file name
        CNOP    0,4
outbuf  ds.b    128             ;buffer for output file path name
dirbuf  ds.b    128

strwork ds.b    128             ;buffer for BSTR conversion
wk_lgth equ     *

        END
