;----------------------------------------------------------------------------
;    stat.asm  v1.100       Copyright 1988 by Josh Rovero
;    03 Oct 88                                5449 Beaufain Blvd
;                                             Virginia Beach, VA 23464
;
;                           E-Mail: Nexus BBS 804-547-1065
;
;    Permission is granted for unlimited non-commercial use
;
;    A manual translation of James M. Synge's stat.c to assembly language.
;    Synge's stat is more useful to programmers than the AmigaDos or ARP
;    status commands because it shows where each command is loaded into
;    memory.  All variable storage is on a stack frame so the code is
;    "pure".  My thanks to James Synge for his original program and
;    source, and to Bill Hawes for some constructive criticism and
;    encouragement. It was fun (*&^%$#!!!), educational, and shows again
;    that people make better C compilers than programs do....
;
;    Note:  arp.library V34+ required.
;
;    Features:   Only 524 bytes! One tenth the size of the original compiled
;                C version.  27% smaller than even the ARP status command!
;                Can be installed as a resident command under ARP and WShell.
;
;    tools:   Inovatronics CAPE and Howe's Asm68k 1.2.1
;             Nesbitt's small.lib
;             Software Distillery Blink 6.9 and make
;             ARP
;             SLADE Software Amiga Debugger
;             The Amigan Journeyman and Apprentice
;----------------------------------------------------------------------------

     option nl
     include "libraries/arpbase.i"
     include "exec/memory.i"
     include "exec/tasks.i"
     include "libraries/dosextens.i"
     option l

; Take advantage of optimization if assembled with C.A.P.E.68k
     IFD         CAPE
     TRASHREG    d7
     OPTIMON
     ENDC

;    This structure will exist on the stack frame
;    a5 is our frame pointer -- don't use it for anything else!

fp   equr      a5
     STRUCTURE frame,0
        LONG   processes
        LONG   cli
        LONG   tasknum
        LONG   pri
        APTR   pr
        APTR   str_buf_1_ptr
        APTR   str_buf_2_ptr
        STRUCT str_buf_1,32
        STRUCT str_buf_2,32
        LABEL frame_size

     section one,code,public
     xref  AbsExecBase,_LVOOpenLibrary,_LVOFindTask
     xref  _LVOForbid,_LVOPermit

; See the ARP programmer's docs for RESIDENT and OPENARP macro defs
     RESIDENT 4000,frame_size
     OPENARP  NONDEFAULT
     link     fp,#-frame_size         ; set up the frame pointer
     lea      str_buf_1(sp),a0        ; set up ptr to string buffer 1
     move.l   a0,str_buf_1_ptr(sp)
     lea      str_buf_2(sp),a0        ; set up ptr to string buffer 2
     move.l   a0,str_buf_2_ptr(sp)

; Find the maximum number of CLI processes  (20 in AmigaDos 1.2)
     moveq.l  #0,d0
     LINKEXE  Forbid
     LINKDOS  FindCLI
     move.l   d0,processes(sp)
     LINKEXE  Permit

; Print the report header
     lea      report_header,a1
     LINKDOS  Puts

;    Main Program Loop -- gets task number, priority, load address
;                         task name, and its current directory.

              move.l   processes(sp),d7  ; d7 = max possible # of CLIs
              moveq.l  #0,d6             ; d6 = loop counter
              LINKEXE  Forbid

loop.outer:
              addq.l   #1,d6
              cmp.l    d6,d7             ; check loop limits
              bmi      exit_ok
              move.l   d6,d0
              move.l   d6,tasknum(sp)    ; store the task number
              LINKDOS  FindCLI
              move.l   d0,pr(sp)         ; store process structure pointer
              tst.l    d0
              beq      loop.outer        ; this task isn't a CLI
              move.l   pr(sp),a4
              move.b   LN_PRI(a4),d0     ; get priority of process
              ext.w    d0
              ext.l    d0
              move.l   d0,pri(sp)        ; store priority
              move.l   pr_CLI(a4),d5     ; get CLI BPTR
              asl.l    #2,d5             ; convert to APTR
              move.l   d5,cli(sp)        ; store cli pointer
              move.l   d5,a4
active        lea      str_buf_1(sp),a0
              move.l   a0,str_buf_1_ptr(sp)
              move.l   cli_CommandName(a4),d0  ; get the command name
              move.l   #31,d1
              LINKDOS  BtoCStr
              tst.l    d0
              bne      running

inactive_cli  lea      waiting_msg,a0          ; if not active say "waiting"
              move.l   a0,str_buf_1_ptr(sp)

running       lea      str_buf_2(sp),a0        ; get the CLI's directory
              move.l   a0,str_buf_2_ptr(sp)
              move.l   cli_SetName(a4),d0
              move.l   #31,d1
              LINKDOS  BtoCStr

print         lea      format_string,a0
              lea      tasknum(sp),a1           ;start of Printf args in mem
              LINKDOS  Printf
endloop.outer bra      loop.outer

exit_ok       LINKEXE  Permit
              moveq.l  #0,d0    ; clean up and exit
              unlk     fp
              LINKDOS  ArpExit
              rts

              cnop     0,2
report_header dc.b     'Task Pri  Address Command'
              dc.b     '                          Directory',0
              cnop     0,2
format_string dc.b     '%3ld %4ld %8lx %-32ls %ls',$0a,0
              cnop     0,2
waiting_msg   dc.b     'Waiting...',0
              end
