
*************************************
*    ASSEMBLY PROGRAM:  TCB.asm     *
*     15 July 1987,  Al Aburto      *
*                                   *
*   Scans Amiga Task Control Block  *
*   Structures and DOS SegLists.    *
*************************************

   INCLUDE  "exec/types.i"
   INCLUDE  "exec/execbase.i"
   INCLUDE  "exec/nodes.i"
   INCLUDE  "exec/memory.i"
   INCLUDE  "libraries/dos.i"
   INCLUDE  "libraries/dosextens.i"

   XREF     _AbsExecBase
   XREF     _LVOOpenLibrary
   XREF     _LVOCloseLibrary
   XREF     _LVOFindTask
   XREF     _LVOForbid
   XREF     _LVOPermit

   XREF     _LVOInput
   XREF     _LVOOutput
   XREF     _LVOClose

   XREF     _printf                    ;Routine defined in amiga.lib

*********************** Exported Parameters ****************************

   XDEF     _DOSBase                   ;Define For amiga.lib Routines.
   XDEF     _stdin
   XDEF     _stdout
   XDEF     _stderr

*********************** Main Entry Point ********************************
_main:
            MOVE.L   A7,DOS_SP            ;Save Stack Pointer.
            MOVE.L   A0,DOSCmdBuf         ;CLI Command Buffer Address.
            CLR.B    -$01(A0,D0)          ;Null Terminate CLI Command
                                          ;Argument String.
            BSR      Remove_Trailing_Spaces
            MOVE.L   D0,DOSCmdLen         ;CLI Command Length.

            SUBA.L   A1,A1                ;Find And Initialize Our Task.
            MOVEA.L  _AbsExecBase,A6
            JSR      _LVOFindTask(A6)
            MOVE.L   D0,MyTaskCB          ;Our Task Control Block Pointer
            MOVEA.L  D0,A0                ;Set Name Of This Task (TCB).
            MOVE.L   #MyTaskName,LN_NAME(A0)

            BSR      OpenDOS              ;Open AmigaDOS
            BEQ      QuitA

            BSR      GetStdIO             ;Set Standard IO
            BEQ      QuitB

            MOVEA.L  DOSCmdBuf,A1         ;Pointer To CLI Command String.
            TST.B    (A1)                 ;No Argument If NULL.
            BEQ      Task_List            ;Print Out Task Status List Then.
                                          ;'TCB<cr>' Was Input.

            CMPI.W   #$3F00,(A1)          ;'TCB ?<cr>' Input?
            BEQ      Command_Formats      ;Yes--- Print Command Formats.

            CMPI.W   #$5420,(A1)          ;'TCB T TaskName<cr>' Input?
            BEQ      Dump_TCB             ;Yes--- Do Hex/ASCII Dump of TCB
            CMPI.W   #$7420,(A1)
            BEQ      Dump_TCB

            CMPI.W   #$4320,(A1)          ;'TCB C TaskName<cr>' Input?
            BEQ      Dump_CLI             ;Yes--- Do Hex/ASCII Dump of CLI
            CMPI.W   #$6320,(A1)
            BEQ      Dump_CLI

            CMPI.W   #$4420,(A1)          ;'TCB D HexAddress<cr>' Input?
            BEQ      Dump_Page            ;Yes--- Do Hex/ASCII Dump.
            CMPI.W   #$6420,(A1)
            BEQ      Dump_Page

            CMPI.W   #$4220,(A1)          ;'TCB B BPTR<cr>' Input?
            BEQ      Convert_BPTR         ;Yes--- Convert BPTR To PTR
            CMPI.W   #$6220,(A1)
            BEQ      Convert_BPTR

            CMPI.W   #$4453,(A1)          ;'TCB DS<cr>' Input?
            BEQ      DOS_Structures       ;Yes--- Do Hex/ASCII Dump From
                                          ;   --- DOSLibrary Base Address.
            CMPI.W   #$6473,(A1)
            BEQ      DOS_Structures

            CMPI.W   #$444C,(A1)          ;'TCB DL<cr>' Input?
            BEQ      Scan_DevList         ;Yes--- Print DOS DevList Info.
            CMPI.W   #$646C,(A1)
            BEQ      Scan_DevList

            CMPI.W   #$4C00,(A1)          ;'TCB L<cr>' Input?
            BEQ      Scan_Libraries       ;Yes--- Print Exec Library Info.
            CMPI.W   #$6C00,(A1)
            BEQ      Scan_Libraries

            CMPI.W   #$4400,(A1)          ;'TCB D<cr>' Input?
            BEQ      Scan_Devices         ;Yes--- Print Device Lib Info.
            CMPI.W   #$6400,(A1)
            BEQ      Scan_Devices

            CMPI.W   #$5320,(A1)          ;'TCB S SegListAddress' Input?
            BEQ      SegList_Address      ;Yes--- Print SegList.
            CMPI.W   #$7320,(A1)
            BEQ      SegList_Address
                                          ;No --- Then Assume
                                          ;   --- 'TCB TaskName<cr>' Input.

************************ TaskStatus TaskName ******************************
*** Print Start Address and Size Of All TaskName Code/Data Segments.
*** Task Info Also Printed.  Task Must Be a Process.
***
TaskName_Input:
            MOVE.L   A1,TaskNamePtr
            JSR      _LVOFindTask(A6)     ;A1 Points To TaskName Input.
            TST.L    D0
            BEQ      TNIAE                ;Can't Find Exec Task--Check CLI.
            MOVE.L   D0,TaskPointer       ;Pointer (Address) To Task
                                          ;Control Block Structure.
TNIAA:      MOVEA.L  TaskPointer,A1
            CMPI.B   #$0D,LN_TYPE(A1)     ;Is It A Process?
            BNE      Dump_CLI_Error       ;No! --- Exit Then.

            PEA.L    PrtHdr02             ;Print Header Info
            JSR      _printf
            ADDQ.L   #$04,A7

            BSR      MTForbid
            BSR      TaskInfo             ;Print Task Info
            BSR      MTPermit

Scan_SegList:
            TST.L    Error_Flag           ;Check For SegList Error.
            BNE      SegList_Error

            PEA.L    PrtFmtA              ;Print Header For Segment List.
            JSR      _printf
            ADDQ.L   #$04,A7

            MOVEQ.L  #$03,D0              ;Setup To Do Hex/ASCII Dump Too.
            MOVE.L   D0,NumLWords
            LEA.L    PrtFmtBA,A1
            MOVE.L   A1,ASC_Buffer        ;Where We Put The ASCII Hex Data
            LEA.L    PrtFmtBB,A1
            MOVE.L   A1,PRT_Buffer        ;Where We Put The ASCII Data
            MOVE.L   #$000C,NumChar       ;Only 12 Hex and ASCII Characters.
            CLR.L    Save_Reg

            BSR      MTForbid             ;Forbid Any NEW Multitasking.
TNIAC:      ADDQ.L   #$01,Save_Reg
            MOVE.L   CodeAddress,Hex_Buffer
            BSR      FilterByte           ;ASCII Data For Start Of Segment
            BSR      BinHex               ;Hex   Data For Start Of Segment

            MOVE.L   CodeSize,-(A7)       ;Code Size.
            MOVE.L   CodeAddress,-(A7)    ;Code Address.
            MOVE.L   Save_Reg,-(A7)       ;Segment Number.
            PEA.L    PrtFmtB
            JSR      _printf
            LEA.L    $10(A7),A7

            TST.L    NextSegment          ;Is The Next Segment NULL?
            BEQ      TNIAD                ;Yes --- Quit Then.
            MOVE.L   NextSegment,SegLAddress
            BSR      First_Code
            BRA      TNIAC                ;Do It Again Until We Print All
                                          ;Segment Locations And Size.
TNIAD:      BSR      MTPermit
            BRA      QuitC

TNIAE:      BSR      CLI_TaskArray
            TST.L    Error_Flag
            BEQ      TNIAA
            BRA      Task_Not_Found

********************* Scan SegList Given Initial Address ****************
*** Requires First SegList Address.

SegList_Address:
            LEA.L    $02(A1),A1           ;Get SegList Start Address.
            MOVE.L   A1,ASC_Buffer
            BSR      HexBin               ;Convert ASCII Hex To Hex
            MOVE.L   Save_Reg,SegLAddress ;The Input SegList Address(Hex)
            BSR      First_Code           ;Get Segment Info
            BRA      Scan_SegList         ;Ok --- Go Scan The Rest.

********************* SegList Error Detected! ***************************
SegList_Error:
            MOVE.L   Error_Addr,-(A7)     ;Print Error Message.
            PEA.L    PrtFmtF
            JSR      _printf
            LEA.L    $08(A7),A7
            MOVE.L   Error_Addr,Save_Reg
            BRA      Dump_PageA           ;Do Hex/ASCII Dump At Error
                                          ;Address.

********************* Task Not Found Message ****************************
Task_Not_Found:
            PEA.L    PrtNoTask
            JSR      _printf
            ADDQ.L   #$04,A7
            BRA      QuitC

******************** Command Formats List *******************************
Command_Formats:
            PEA.L    CmdFormatA           ;Need 4 _printf's As _printf
            JSR      _printf              ;will Crash System If String To
            ADDQ.L   #$04,A7              ;Print Is Too Big. 180 Characters
                                          ;appears to be max.
            PEA.L    CmdFormatB
            JSR      _printf
            ADDQ.L   #$04,A7

            PEA.L    CmdFormatC
            JSR      _printf
            ADDQ.L   #$04,A7

            PEA.L    CmdFormatD
            JSR      _printf
            ADDQ.L   #$04,A7

            BRA      QuitC

******************** Convert BPTR To PTR (68000 Address) ****************
Convert_BPTR:
            LEA.L    $02(A1),A1           ;Get Input BPTR.
            MOVE.L   A1,ASC_Buffer
            BSR      HexBin
            MOVE.L   Save_Reg,D0
            MOVE.L   D0,D1
            LSL.L    #$02,D1              ;Convert To APTR.

            MOVE.L   D1,-(A7)             ;Print Results.
            MOVE.L   D0,-(A7)
            PEA.L    PrtFmtE
            JSR      _printf
            LEA.L    $0C(A7),A7
            BRA      QuitC

******************** Dump Hex/ASCII Data From Input Address *************
Dump_Page:
            LEA.L    $02(A1),A1           ;Get Dump Address.
            MOVE.L   A1,ASC_Buffer
            BSR      HexBin               ;Convert ASCII Hex To Hex.
Dump_PageA: MOVE.L   Save_Reg,Hex_Buffer  ;Where We Start The Dump.
            MOVE.L   Save_Reg,StartAddr   ;Use This As Hex_Buffer Varies.
            BRA      Dump_Hex_ASCII       ;Go Do It.

******************** Dump Hex/ASCII Data From TCB Address ***************
Dump_TCB:
            LEA.L    $02(A1),A1           ;Get Input TaskName Strg Address.
            MOVE.L   A1,TaskNamePtr
            JSR      _LVOFindTask(A6)     ;Check For Match In Exec Tasks.
            TST.L    D0
            BEQ      DTCBB                ;Exec Task Not Found. Check CLI.
            MOVE.L   D0,TaskPointer

DTCBA:      MOVE.L   TaskPointer,Hex_Buffer
            CLR.L    StartAddr

            MOVE.L   TaskPointer,-(A7)    ;Print Header Info.
            PEA.L    PrtFmtD04
            JSR      _printf
            ADDQ.L   #$08,A7
            BRA      Dump_Hex_ASCII       ;Go Do The Hex/ASCII Dump.

DTCBB:      BSR      CLI_TaskArray        ;Check For CLI Tasks.
            TST.L    Error_Flag
            BEQ      DTCBA                ;CLI Task Found.
            BRA      Task_Not_Found

******************** Dump DOS Structures ********************************
DOS_Structures:
            PEA.L    PrtFmtG01            ;Print Header
            JSR      _printf
            ADDQ.L   #$04,A7

            MOVEA.L  _DOSBase,A0          ;DosLibrary Node Base Address.
            MOVEA.L  LIB_SIZE(A0),A1      ;RootNode Structure Address.
            MOVE.L   A1,Save_Reg
            MOVE.L   (A1),D0              ;rn_TaskArray BPTR.
            LSL.L    #$02,D0              ;rn_TaskArray APTR.

            MOVE.L   D0,-(A7)             ;Print It.
            MOVE.L   A1,-(A7)
            MOVE.L   A0,-(A7)
            PEA.L    PrtFmtG02
            JSR      _printf
            LEA.L    $10(A7),A7

            MOVEA.L  Save_Reg,A0
            MOVE.L   rn_Info(A0),D0       ;DevInfo Structure Address.
            LSL.L    #$02,D0
            MOVEA.L  D0,A0
            MOVE.L   $04(A0),D0           ;DevList Structure Address.
            LSL.L    #$02,D0

            MOVE.L   D0,-(A7)             ;Print It.
            MOVE.L   A0,-(A7)
            PEA.L    PrtFmtG03
            JSR      _printf
            LEA.L    $0C(A7),A7

            BRA      QuitC

******************** Scan DOS DevList Structures ************************
Scan_DevList:
            PEA.L    PrtFmtH01
            JSR      _printf
            ADDQ.L   #$04,A7

            MOVEA.L  _DOSBase,A0
            MOVEA.L  dl_Root(A0),A0
            MOVE.L   rn_Info(A0),D0
            LSL.L    #$02,D0
            MOVEA.L  D0,A0
            MOVE.L   di_DevInfo(A0),D0
            LSL.L    #$02,D0
            MOVEA.L  D0,A0                ;DevList Structure Address.

ScanDevL1:  MOVE.L   A0,Save_Reg

            MOVE.L   $28(A0),D0           ;DevList Structure Name.
            LSL.L    #$02,D0
            ADDQ.L   #$01,D0
            MOVEA.L  D0,A4

            MOVE.L   $20(A0),D0           ;SegList
            LSL.L    #$02,D0
            MOVEA.L  D0,A3

            MOVEA.L  $08(A0),A2           ;DevList Type.
            LEA.L    Dev_Type,A1
            MOVE.L   $04(A0),D0
            MOVE.L   D0,D1
            MULU.W   #$000A,D0
            ADDA.L   D0,A1

            CMPI.B   #$02,D1
            BNE      ScanDevL2
            SUBA.L   A3,A3

ScanDevL2:  MOVE.L   A4,-(A7)
            MOVE.L   A3,-(A7)
            MOVE.L   A2,-(A7)
            MOVE.L   A1,-(A7)
            MOVE.L   A0,-(A7)
            PEA.L    PrtFmtH02
            JSR      _printf
            LEA.L    $18(A7),A7

            MOVEA.L  Save_Reg,A1
            MOVE.L   (A1),D0
            LSL.L    #$02,D0
            MOVEA.L  D0,A0                ;Next DevList Structure Address.
            TST.L    (A1)                 ;Quit On Null.
            BNE      ScanDevL1            ;Go Print Next.
            BRA      QuitC

******************** Scan Amiga Library Structures **********************
Scan_Libraries:
            PEA.L    PrtFmtI01
            JSR      _printf              ;Print Header.
            ADDQ.L   #$04,A7

            MOVEA.L  _AbsExecBase,A6
            MOVEA.L  LibList(A6),A0       ;Library List Structure Pointer.

ScanLiba:   MOVE.L   A0,Save_Reg          ;Save A0 as _printf Clobbers It.
            TST.L    (A0)
            BEQ      ScanLibd             ;End Of List --- Quit.

            MOVE.L   LIB_IDSTRING(A0),D0
            BNE      ScanLibb
            MOVE.L   #Default_Str,D0
            BRA      ScanLibc

ScanLibb:   BSR      Null_Terminate
ScanLibc:   MOVE.L   D0,-(A7)             ;D0 Contains LIB_IDSTRING Pointer.
            MOVE.W   LIB_POSSIZE(A0),-(A7)
            MOVE.W   LIB_NEGSIZE(A0),-(A7)
            MOVE.L   LN_NAME(A0),-(A7)    ;Library Name.
            MOVE.L   A0,-(A7)             ;Library Address.
            PEA.L    PrtFmtI02            ;Print Format String.
            JSR      _printf              ;Print Routine.
            LEA.L    $14(A7),A7           ;Restore Stack Pointer.
            MOVE.L   Save_Reg,A0
            MOVE.L   (A0),A0              ;Get Next Node Pointer.
            BRA      ScanLiba

ScanLibd:   BRA      QuitC

******************** Scan Amiga Device Libraries ************************
Scan_Devices:
            PEA.L    PrtFmtI01
            JSR      _printf
            ADDQ.L   #$04,A7

            MOVEA.L  _AbsExecBase,A6
            MOVEA.L  DeviceList(A6),A0
            BRA      ScanLiba

******************** General Hex/ASCII Dump Routine *********************
Dump_Hex_ASCII:
            MOVEQ.L  #$04,D0
            MOVE.L   D0,NumLWords
            LSL.L    #$02,D0
            MOVE.L   D0,NumChar
            MOVE.L   #$0010,NumRows
            MOVEQ.L  #$00,D0
            MOVE.L   StartAddr,D1

            LEA.L    PrtFmtCA,A0
            MOVE.L   A0,ASC_Buffer
            LEA.L    PrtFmtCB,A1
            MOVE.L   A1,PRT_Buffer

            BSR      MTForbid
DHALoop:    ADDQ.L   #$01,D0
            BSR      FilterByte
            BSR      BinHex

            MOVEM.L  D0/D1,-(A7)
            MOVE.L   D1,-(A7)
            PEA.L    PrtFmtC
            JSR      _printf
            ADDQ.L   #$08,A7
            MOVEM.L  (A7)+,D0/D1

            ADD.L    NumChar,D1
            CMP.L    NumRows,D0
            BNE      DHALoop

            BSR      MTPermit
            BRA      QuitC

******************** Dump CommandLineInterface Structure *****************
Dump_CLI:
            LEA.L    $02(A1),A1           ;Input TaskName Pointer.
            MOVE.L   A1,TaskNamePtr
            JSR      _LVOFindTask(A6)
            TST.L    D0
            BEQ      DCLID                ;Check CLI Tasks Then
            MOVE.L   D0,TaskPointer

DCLIA:      MOVEA.L  TaskPointer,A0
            CMPI.B   #$0D,LN_TYPE(A0)     ;Is It A Process?
            BNE      Dump_CLI_Error       ;Error --- Not A Process.

DCLIB:      MOVE.L   pr_CLI(A0),D0        ;BPTR To CLI Structure
            TST.L    D0                   ;CLI ?
            BEQ      DCLIC                ;No  --- Print Error.

            LSL.L    #$02,D0              ;APTR To CLI Structure
            MOVE.L   D0,Hex_Buffer
            CLR.L    StartAddr

            MOVE.L   D0,-(A7)             ;Print Header.
            PEA.L    PrtFmtD01
            JSR      _printf
            ADDQ.L   #$08,A7
            BRA      Dump_Hex_ASCII       ;Go Do The Hex/ASCII Dump.

DCLIC:      PEA.L    PrtFmtD03            ;Error --- Not CLI Process.
            JSR      _printf
            ADDQ.L   #$04,A7
            BRA      QuitC

DCLID:      BSR      CLI_TaskArray        ;Check DOS CLI rn_TaskArray.
            TST.L    Error_Flag
            BEQ      DCLIA                ;Found DOS CLI Task.
            BRA      Task_Not_Found

Dump_CLI_Error:
            PEA.L    PrtFmtD02            ;Error --- Not a Process.
            JSR      _printf
            ADDQ.L   #$04,A7
            BRA      QuitC

******************** Print Out Info On All Current Tasks *****************
Task_List:
            PEA.L    PrtHdr01             ;Print Program Title.
            JSR      _printf
            ADDQ.L   #$04,A7

            PEA.L    PrtHdr03             ;Print Header For Output.
            JSR      _printf
            ADDQ.L   #$04,A7

            MOVEA.L  ThisTask(A6),A0      ;Pointer To Current Task Structure
            MOVE.L   A0,TaskPointer

            BSR      MTForbid
            MOVE.L   pr_CLI(A0),D0
            TST.L    D0
            BEQ      TL01                 ;Not CLI --- Skip The Rest As It
                                          ;        --- Is Not Valid.
            LSL.L    #$02,D0
            MOVEA.L  D0,A1                ;CommandLineInterpreter Structure.
            MOVE.L   cli_Module(A1),D0    ;Current Command SegList Pointer.
            LSL.L    #$02,D0              ;Convert From BCPL
            MOVEA.L  D0,A1                ;Pointer To SegList.
            MOVE.L   A1,SegLAddress
            MOVE.L   pr_SegList(A0),D0    ;BPTR To SegList Array
            LSL.L    #$02,D0
            MOVE.L   D0,SegListArray
            BSR      First_Code
            BSR      TaskInfoB
TL01:

Tasks_Waiting:
            MOVEA.L  TaskWait(A6),A0      ;Task Control Block Pointer Of
            MOVE.L   A0,TaskPointer       ;Waiting Tasks.
            BSR      TaskInfo
            MOVEA.L  TaskPointer,A0
            TST.L    (A0)                 ;Is Next Node Null?
            BEQ      Tasks_Ready          ;Yes --- Done Then.

            CLR.L    Loop_Done
TW01:       BSR      Get_Task
            TST.L    Loop_Done            ;Loop Until We Get All Waiting
            BEQ      TW01                 ;Tasks.

Tasks_Ready:
            MOVEA.L  TaskReady(A6),A0     ;Check 'Ready' Tasks.
            MOVE.L   A0,TaskPointer       ;Task Node Pointer.
            BSR      TaskInfo             ;Print Info.
            MOVEA.L  TaskPointer,A0       ;Get Current Task Pointer
            TST.L    (A0)                 ;Is Next Node Null?
            BEQ      TR02                 ;Yes --- Quit Then.

            CLR.L    Loop_Done
TR01:       BSR      Get_Task
            TST.L    Loop_Done
            BEQ      TR01
TR02:       BSR      MTPermit

QuitC:      ;I did Have an _LVOClose here but it resulted in System Crash!
            ;I Dunno Why --- So I Removed That Code --- Works OK Now.
QuitB:

******************** End Of Program Run ***********************************
QuitA:      CLR.L    D0                   ;End Of Program Run.
            MOVEA.L  DOS_SP,A7
            RTS

*<<<<<<<<<<<<<<<<<<<<<<<<< Subroutines >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*

*************** Check DOS CLI[n] TaskArray *****************************
CLI_TaskArray:
            CLR.L    Error_Flag
            MOVEA.L  _DOSBase,A2
            MOVEQ.L  #$00,D1              ;CLI Task Counter --- Preserve
            MOVEA.L  dl_Root(A2),A2       ;RootNode Structure Address
            MOVE.L   (A2),D0              ;rn_TaskArray (BPTR)
            LSL.L    #$02,D0
            MOVEA.L  D0,A2                ;rn_TaskArray Address
            MOVE.L   (A2)+,D2             ;Max # Elements ----- Preserve
            ADDQ.L   #$01,D2

CTA01:      TST.L    (A2)                 ;Null Pointer?
            BEQ      CTA09                ;Yes --- Quit
            MOVEA.L  (A2)+,A1             ;CLI[1] (APTR) --- Process-id
            ADDQ.L   #$01,D1              ;Increment Task Count
            CMP.L    D1,D2
            BEQ      CTA09                ;Error --- Quit Then.

            LEA.L    -TC_SIZE(A1),A0
            MOVE.L   A0,TaskPointer
            CMPI.B   #$0D,LN_TYPE(A0)     ;Process?
            BNE      CTA10                ;No  --- Quit
            MOVE.L   pr_CLI(A0),D0
            TST.L    D0                   ;CLI?
            BEQ      CTA10                ;No  --- Quit.
            LSL.L    #$02,D0
            MOVEA.L  D0,A1                ;CommandLineInterface Structure
            MOVE.L   cli_CommandName(A1),D0
            LSL.L    #$02,D0
            MOVEA.L  D0,A1                ;CLI TaskName Address (a BSTR)
            MOVE.B   (A1)+,D0             ;Number Of Characters.
            MOVEA.L  TaskNamePtr,A0       ;Input TaskName.
            BSR      String_Cmp
            TST.L    D0                   ;String Match?
            BNE      CTA01                ;No  --- Check Next CLI Task.

            RTS

CTA09:      ADDQ.L   #$01,Error_Flag      ;Task_Not_Found
            RTS

CTA10:      ADDQ.L   #$02,Error_Flag      ;Not a CLI Process
            RTS

*************** Compare Memory *****************************************
String_Cmp:
            MOVEM.L  D1-D2/A0-A2,-(A7)
Str_Cmp_Loop:
            CMPM.B   (A0)+,(A1)+
            BNE      Str_Cmp_False
            SUBQ.L   #$01,D0
            CMPI.B   #$01,D0
            BNE      Str_Cmp_Loop
            MOVEQ.L  #$00,D0
Str_Cmp_Rts:
            MOVEM.L  (A7)+,D1-D2/A0-A2
            RTS
Str_Cmp_False:
            MOVEQ.L  #$01,D0
            BRA      Str_Cmp_Rts

*************** Remove Trailing Spaces From String *********************
Remove_Trailing_Spaces:
            MOVEM.L  D1/A1,-(A7)
            MOVEA.L  A0,A1                ;A0 --> Start Of String.
            LEA.L    -$01(A0,D0),A1       ;D0 Is Length Of String.
                                          ;A1 --> End   Of String
RTS01:      CMPI.B   #$20,-(A1)           ;Space?
            BNE      RTS02                ;No  --- Quit Then.

            SUBQ.L   #$01,D0              ;Reduce Length By One.
            MOVE.B   #$00,(A1)            ;Null Terminate.
            BRA      RTS01                ;Keep Checking.

RTS02:      MOVEM.L  (A7)+,D1/A1          ;D0 Contains Length Of New
            RTS                           ;Null Terminated String.

*************** Null Terminate ASCII String ****************************
Null_Terminate:
            MOVEM.L  D1/A0/A1,-(A7)
            MOVE.L   D0,A0                ;ASCII String Pointer.
            MOVEA.L  #ASCIIBuff,A1
            MOVE.L   A1,D0                ;Final String Location.

NullTerma:  MOVE.B   (A0)+,D1
            CMPI.B   #$0D,D1              ;Quit If CR Found.
            BEQ      NullTermb
            CMPI.B   #$0A,D1              ;Quit If LF Found.
            BEQ      NullTermb
            CMPI.B   #$00,D1              ;Quit If NULL Found.
            BEQ      NullTermb
            MOVE.B   D1,(A1)+
            BRA      NullTerma

NullTermb:  MOVE.B   #$00,(A1)+           ;NULL Terminate And Quit.
            MOVE.B   #$00,(A1)+           ;D0 Holds New String Pointer
            MOVEM.L  (A7)+,D1/A0/A1       ;Address.
            RTS

*************** Filter Byte For Printing *******************************

FilterByte: MOVEM.L  D0-D2/A0-A1,-(A7)    ;Convert ASCII Control Codes
            MOVEA.L  Hex_Buffer,A0        ;To '.' For ASCII Dump.
            MOVEA.L  PRT_Buffer,A1
            MOVE.L   NumChar,D2
            MOVEQ.L  #$00,D1

FBLoop:     ADDQ.L   #$01,D1
            MOVE.B   (A0)+,D0
            CMPI.B   #$20,D0
            BLT      SetPeriod
            CMPI.B   #$7D,D0
            BGT      SetPeriod
            CMPI.B   #$25,D0
            BEQ      SetSpecial

PrtOk:      MOVE.B   D0,(A1)+
            CMP.L    D1,D2
            BNE      FBLoop
            MOVEM.L  (A7)+,D0-D2/A0-A1
            RTS

SetPeriod:  MOVE.B   #$2E,D0
            BRA      PrtOk
SetSpecial: MOVE.B   #$B6,D0
            BRA      PrtOk

*************** Convert ASCII Hex Character To Long Hex  ****************
*** Only Input Required Is ASCII Hex String Address: ASC_Buffer

HexBin:     MOVEM.L  D0-D2/A0-A2,-(A7)
            MOVEQ.L  #$00,D0
            MOVEA.L  ASC_Buffer,A0        ;ASCII Hex String Address.

HBLoopA:    MOVEQ.L  #$00,D1
            CMPI.B   #'9',(A0)            ;Is It > $39 ?
            BHI      NotDec               ;Yes --- Check For A,B,C,D,E,F
            CMPI.B   #'0',(A0)            ;Is It < $30 ?
            BLT      NotHex               ;Yes --- Quit Then.
            MOVE.B   #'0',D1
            BRA      GotDigit             ;Must Be $30 Through $39 Then

NotDec:     CMPI.B   #'A',(A0)            ;Is It < $41 ?
            BLT      NotHex               ;Yes --- Quit Then.
            CMPI.B   #'F',(A0)            ;Is It > $46 ?
            BHI      NotUC                ;Yes --- Check Lower Case Then.
            MOVE.B   #'A'-10,D1
            BRA      GotDigit             ;Must Be A,B,C,D,E, or F Then.

NotUC:      CMPI.B   #'a',(A0)
            BLT      NotHex
            CMPI.B   #'f',(A0)
            BHI      NotHex
            MOVE.B   #'a'-10,D1

GotDigit:   MOVEQ.L  #$00,D2
            MOVE.B   (A0)+,D2
            SUB.L    D1,D2
            LSL.L    #$04,D0
            ADD.L    D2,D0
            BRA      HBLoopA

NotHex:     MOVE.L   D0,Save_Reg          ;Save_Reg Holds 4 Byte Result.
            MOVEM.L  (A7)+,D0-D2/A0-A2
            RTS

*************** Convert Nibble To ASCII Hex Character ******************
*************** A2  =  Hex Buffer (4 Bytes)
*************** A0 --> Output ASCII Hex Buffer (8 Bytes)

BinHex:     MOVEM.L  D0-D3/A0-A2,-(A7)
            LEA.L    HexTable,A1
            MOVEA.L  ASC_Buffer,A0
            MOVEQ.L  #$00,D3
            MOVEA.L  Hex_Buffer,A2

BHLoopA:    ADDA.L   #$0008,A0
            MOVEQ.L  #$07,D1
            ADDQ.L   #$01,D3
            MOVE.L   (A2)+,D0

BHLoopB:    MOVE.L   D0,D2
            ANDI.L   #$0000000F,D2
            MOVE.B   $00(A1,D2.L),-(A0)
            LSR.L    #$04,D0
            DBRA     D1,BHLoopB

            LEA.L    $09(A0),A0
            CMP.L    NumLWords,D3
            BNE      BHLoopA

            MOVE.L   A2,Hex_Buffer
            MOVEM.L  (A7)+,D0-D3/A0-A2
            RTS

*************** Open DOS Library ***************************************
OpenDOS:    LEA.L    DOSName,A1
            MOVEA.L  _AbsExecBase,A6
            MOVEQ.L  #$00,D0
            JSR      _LVOOpenLibrary(A6)
            MOVE.L   D0,_DOSBase
            RTS

*************** Get Std IO File Handles ********************************
GetStdIO:   MOVE.L   A6,-(A7)
            MOVEA.L  _DOSBase,A6
            JSR      _LVOInput(A6)
            MOVE.L   D0,_stdin
            BEQ      GSIORTS

            JSR      _LVOOutput(A6)
            MOVE.L   D0,_stdout
            MOVE.L   D0,_stderr
GSIORTS:    MOVE.L   (A7)+,A6
            TST.L    D0
            RTS

*************** Get First Code Address Info ****************************
*** Only Required Input Is The SegList Address Pointer (SegLAddress)

First_Code: MOVEM.L  D0-D1/A0-A1,-(A7)
            CLR.L    Error_Flag
            MOVE.L   SegLAddress,A1       ;Pointer To SegList Address
            MOVE.L   (A1),D1              ;BPTR To Next Segment
            CMPI.L   #$3FFFFFFF,D1        ;Max BPTR Exceeded?
            BLE      FC01
            MOVE.L   #$0001,Error_Flag
            MOVE.L   A1,Error_Addr

FC01:       LSL.L    #$02,D1
            MOVE.L   D1,NextSegment       ;Next Segment Address
            MOVE.L   -$0004(A1),D0        ;Code Size Of First Segment
            MOVE.L   D0,CodeSize
            ADDQ.L   #$04,A1              ;First Segment Address.
            MOVE.L   A1,CodeAddress
            MOVEM.L  (A7)+,D0-D1/A0-A1
            RTS

*************** Get Task Information ***********************************
*** Updates Node TaskPointer And Prints Info On Updated Task

Get_Task:   MOVE.L   A0,-(A7)
            MOVEA.L  TaskPointer,A0       ;Get Task Structure Pointer.
            MOVEA.L  (A0),A0              ;For Next Task.
            TST.L    (A0)                 ;Done If Its Contents Are NULL.
            BEQ      GTExit

            MOVE.L   A0,TaskPointer       ;Save Current Task Structure Ptr.
            BSR      TaskInfo             ;Print The Task Information.
            MOVEA.L  (A7)+,A0
            RTS

GTExit:     ADDQ.L   #$01,Loop_Done       ;Set Flag For Calling Routine.
            MOVEA.L  (A7)+,A0
            RTS

*************** Print Out Task Info *************************************
*** Only Required Input Is The Current TaskPointer --- Dumps Info On That

TaskInfo:   MOVEA.L  TaskPointer,A0
            CLR.L    SegLAddress
            MOVE.L   $80(A0),D0           ;SegList Array BPTR
            LSL.L    #$02,D0              ;Convert To Address
            MOVE.L   D0,SegListArray      ;Save SegList Array Address.
            ADD.L    #$000C,D0            ;Third Long Word Is User Code BPTR
            MOVEA.L  D0,A1                ;Contents A1 Is SegList Address
            MOVE.L   (A1),D0              ;In BCPL (Of Course!)
            BEQ      TI02                 ;Oops!
            LSL.L    #$02,D0
            MOVE.L   D0,SegLAddress       ;SegList Start Address!
            BSR      First_Code           ;Get The Code Address and Size

            CMPI.B   #$0D,$08(A0)         ;Is It A Process?
            BEQ      TaskInfoB            ;Yes --- Go Print The Results.

TI01:       CLR.L    SegListArray         ;No  --- SegList Not Valid Then.
            CLR.L    CodeAddress          ;    --- Start Address Not Valid.
            BRA      TaskInfoB

TI02:       CMPI.B   #$0D,$08(A0)         ;Process?
            BNE      TI01                 ;No  --- Forget The Rest Then.
            MOVE.L   pr_CLI(A0),D0        ;Its Null --- Check cli_Module
            TST.L    D0
            BEQ      TI01                 ;Just Give Up!
            LSL.L    #$02,D0
            MOVEA.L  D0,A1
            MOVE.L   cli_Module(A1),D0    ;BPTR To SegList
            LSL.L    #$02,D0
            MOVEA.L  D0,A1
            MOVE.L   A1,SegLAddress       ;SegList
            BSR      First_Code

TaskInfoB:  MOVE.L   SegListArray,-(A7)   ;SegList Array  Address.
            MOVE.L   TaskPointer,-(A7)    ;Task Structure Address.

            CLR.L    D0
            MOVE.B   $09(A0),D0           ;LN_PRI --- Task Priority.
            EXT.W    D0
            EXT.L    D0
            MOVE.L   D0,-(A7)

            MOVEA.L  #PrtYes,A1
            TST.L    pr_CLI(A0)           ;Was It Run From The CLI?
            BNE      TI03                 ;Yes
            MOVEA.L  #PrtNo,A1
            BRA      TI04

TI03:       CMPI.B   #$0D,LN_TYPE(A0)     ;Set To 'No' If not a Process.
            BEQ      TI04
            MOVEA.L  #PrtNo,A1

TI04:       MOVE.L   A1,-(A7)             ;CLI Task --- Yes Or No Result.

            MOVEQ.L  #$00,D0
            MOVE.B   $0F(A0),D0           ;TC_STATE
            MULU.W   #$0008,D0
            MOVEA.L  #Task_State,A1       ;Pointer To State String.
            ADDA.L   D0,A1
            MOVE.L   A1,-(A7)

            MOVEQ.L  #$00,D0
            MOVE.B   $08(A0),D0           ;LN_TYPE
            MULU.W   #$000A,D0
            MOVEA.L  #NodeType,A1         ;Pointer To Type Of Task String.
            ADDA.L   D0,A1
            MOVE.L   A1,-(A7)             ;Task Type

            TST.B    $08(A0)              ;See If Node Type Is 'Unknown'!
            BEQ      TI06                 ;Print Default Name If Node Type
                                          ;is 'Unknown' To Prevent printing
                                          ;Garbage String!

            MOVEA.L  LN_NAME(A0),A1       ;Exec Task NodeName Pointer.
            CMPI.B   #$0D,LN_TYPE(A0)     ;Process?
            BNE      TI05                 ;No! --- Use LN_NAME.
            MOVE.L   pr_CLI(A0),D0        ;Yes
            TST.L    D0                   ;CLI?
            BEQ      TI05                 ;No! --- Use LN_NAME.
            LSL.L    #$02,D0              ;Its A Process Run From CLI Here.
            MOVEA.L  D0,A2                ;For Process use CLI CommandName.
            MOVE.L   cli_CommandName(A2),D0
            TST.L    D0
            BEQ      TI05
            LSL.L    #$02,D0              ;BSTR Address (Now an APTR)
            ADDQ.L   #$01,D0              ;Skip BSTR Size Byte!
            BSR      Null_Terminate
            MOVEA.L  D0,A1                ;New CommandName String Location.

TI05:       TST.B    $0F(A0)              ;Task State Invalid?
            BNE      TI07                 ;No  --- Branch Then.
TI06:       MOVEA.L  #PrtNoName,A1        ;Yes --- Get Default String.
TI07:       MOVE.L   A1,-(A7)

            PEA.L    PrtFmt
            JSR      _printf
            LEA      $20(A7),A7
TI08:       RTS

*************** Forbid Multitasking *************************************
MTForbid:   MOVE.L   A6,-(A7)
            MOVEA.L  _AbsExecBase,A6
            JSR      _LVOForbid(A6)
            MOVEA.L  (A7)+,A6
            RTS

*************** Permit MultiTasking *************************************
MTPermit:   MOVE.L   A6,-(A7)
            MOVEA.L  _AbsExecBase,A6
            JSR      _LVOPermit(A6)
            MOVEA.L  (A7)+,A6
            RTS

*************** Data Storage ********************************************
            SECTION  data,DATA

            CNOP  0,2
MyTaskName  DC.B     'TCB',0

            CNOP  0,2
DOSName     DC.B     'dos.library',0

            CNOP  0,2
Default_Str DC.B     '*** ( No ID String ) ***',0

            CNOP  0,2
PrtNoName   DC.B     '***( No Name )***',0

            CNOP  0,2
PrtHdr01    DC.B     $0C,$9B,$33,$33,$6D
            DC.B     '   ***************<<<'
            DC.B     $9B,$37,$3B,$33,$31,$6D
            DC.B     ' PD Program TCB, 15 Jul 1987,'
            DC.B     ' By AAA '
            DC.B     $9B,$30,$3B,$33,$33,$6D
            DC.B     '>>>**************'
            DC.B     $9B,$33,$31,$6D,$0A,$00

            CNOP  0,2
PrtHdr02    DC.B     $0C
PrtHdr03    DC.B     $9B,$33,$33,$6D
            DC.B     '   Task Name           Task Type     State    CLI   '
            DC.B     'PRI   Task CB  SegArray'
            DC.B     $9B,$33,$31,$6D,$0A,$00

            CNOP  0,2
PrtFmtA     DC.B     $9B,$33,$33,$6D
            DC.B     '   <<<*********************************'
            DC.B     '*********************************>>>',$0A
            DC.B     $9B,$33,$31,$6D
            DC.B     '   Process Segment List:',$0A
            DC.B     '   Segment   Address      Size',$0A,$00

            CNOP  0,2
PrtYes      DC.B     'Yes',0

            CNOP  0,2
PrtNo       DC.B     'No ',0

            CNOP  0,2
CmdFormatA: DC.B     $0A
            DC.B     $9B,$33,$33,$6D
            DC.B     '   Command Formats: '
            DC.B     $9B,$33,$31,$6D,$0A
            DC.B     '   TCB ?            ;This List',$0A
            DC.B     '   TCB              ;Lists All Tasks',$0A
            DC.B     '   TCB TaskName     ;TaskName Segments',$0A
            DC.B     $00

            CNOP  0,2
CmdFormatB: DC.B     '   TCB T TaskName   ;Task/Process Structure',$0A
            DC.B     '   TCB C TaskName   ;CLI Structure',$0A
            DC.B     '   TCB D HexAddress ;Hex-ASCII Dump',$0A
            DC.B     $00

            CNOP  0,2
CmdFormatC: DC.B     '   TCB B BPTR       ;BPTR --> APTR',$0A
            DC.B     '   TCB DS           ;Other DOS Structures',$0A
            DC.B     '   TCB DL           ;DOS DeviceList Info',$0A
            DC.B     $00

            CNOP  0,2
CmdFormatD: DC.B     '   TCB L            ;Amiga Library Info',$0A
            DC.B     '   TCB D            ;Amiga Device Library Info',$0A
            DC.B     '   TCB S SegListAdr ;Scan SegList',$0A
            DC.B     $0A,$00

            CNOP  0,2
PrtNoTask   DC.B     $0A
            DC.B     $9B,$33,$33,$6D
            DC.B     '   Task Not Found '
            DC.B     $9B,$33,$31,$6D,$0A,$0A,$00

NodeType    DC.B     'UnKnown  ',0
            DC.B     'Task     ',0
            DC.B     'Interrupt',0
            DC.B     'Device   ',0
            DC.B     'MsgPort  ',0
            DC.B     'Message  ',0
            DC.B     'FreeMsg  ',0
            DC.B     'ReplyMsg ',0
            DC.B     'Resource ',0
            DC.B     'Library  ',0
            DC.B     'Memory   ',0
            DC.B     'SoftInt  ',0
            DC.B     'Font     ',0
            DC.B     'Process  ',0
            DC.B     'Semaphore',0
            DC.B     'SignalSem',0

Task_State  DC.B     'Invalid',0
            DC.B     'Added  ',0
            DC.B     'Run    ',0
            DC.B     'Ready  ',0
            DC.B     'Wait   ',0
            DC.B     'Except ',0
            DC.B     'Removed',0

Dev_Type    DC.B     'Device   ',0
            DC.B     'Directory',0
            DC.B     'Volume   ',0

            CNOP  0,2
PrtFmt      DC.B     '   %-18s  %-12s  %-7s  %-3s  %4ld  %8lx  %8lx',10,0

            CNOP  0,2
PrtFmtB     DC.B     '      %4ld  %8lx  %8lx  '
PrtFmtBA    DC.B     'aaaaaaaa bbbbbbbb cccccccc  '
PrtFmtBB    DC.B     '............',$0A,$00

            CNOP  0,2
HexTable    DC.B     '0123456789ABCDEF'

            CNOP  0,2
PrtFmtC     DC.B     '   %8lx: '
PrtFmtCA    DC.B     'aaaaaaaa bbbbbbbb cccccccc dddddddd'
            DC.B     '  '
PrtFmtCB    DC.B     '................'
            DC.B     $20
            DC.B     $0A,$00

            CNOP  0,2
PrtFmtD01   DC.B     '   CommandLineInterface Structure Address = $%8lx'
            DC.B     $0A,$00

            CNOP  0,2
PrtFmtD02   DC.B     $0A,'   Error --- No Process Structure Found'
            DC.B     $0A,$0A,$00

            CNOP  0,2
PrtFmtD03   DC.B     $0A,'   Error --- Not a CLI Process'
            DC.B     $0A,$0A,$00

            CNOP  0,2
PrtFmtD04   DC.B     '   Task/Process Structure Address = $%8lx'
            DC.B     $0A,$00

            CNOP  0,2
PrtFmtE     DC.B     $0A
            DC.B     '   BPTR = $%lx',$0A
            DC.B     '   APTR = $%lx',$0A
            DC.B     $0A,$00

            CNOP  0,2
PrtFmtF     DC.B     $0A
            DC.B     '   BPTR Error Detected At $%lx',$0A,$00

            CNOP  0,2
PrtFmtG01   DC.B     '   Addresses Of Various DOS Structures',$0A,$00

            CNOP  0,2
PrtFmtG02   DC.B     '   DosLibrary    $%lx',$0A
            DC.B     '   RootNode      $%lx',$0A
            DC.B     '   rn_TaskArray  $%lx',$0A,$00

            CNOP  0,2
PrtFmtG03   DC.B     '   DosInfo       $%lx',$0A
            DC.B     '   DevList       $%lx',$0A,$00

            CNOP  0,2
PrtFmtH01   DC.B     '   DOS DevList Structures:',$0A
            DC.B     '    Address  Type            Task   SegList'
            DC.B     '  Name',$0A,$00

            CNOP  0,2
PrtFmtH02   DC.B     '   %8lx  %-10s  %8lx  %8lx  %-20s',$0A,$00

            CNOP  0,2
PrtFmtI01   DC.B     ' Amiga Library Info:',$0A
            DC.B     ' Address  Name                 -Size  +Size'
            DC.B     '   ID String',$0A,$00

            CNOP  0,2
PrtFmtI02   DC.B     '%8lx  %-20s  %4x   %4x   %-30s',$0A,$00

********************* Block Storage **************************************

               SECTION  mem,BSS

DOSCmdBuf:     DS.L     1
DOSCmdLen:     DS.L     1
DOS_SP:        DS.L     1
MyTaskCB:      DS.L     1
_DOSBase:      DS.L     1
_stdin:        DS.L     1
_stdout:       DS.L     1
_stderr:       DS.L     1

TaskPointer:   DS.L     1
TaskNamePtr:   DS.L     1
SegListArray:  DS.L     1
NumSegments:   DS.L     1
SegLAddress:   DS.L     1
CodeAddress:   DS.L     1
CodeSize:      DS.L     1
NextSegment:   DS.L     1
Task_CLI:      DS.L     1

Save_Reg:      DS.L     1
Hex_Buffer:    DS.L     1
ASC_Buffer:    DS.L     1
PRT_Buffer:    DS.L     1
NumLWords:     DS.L     1
Loop_Done:     DS.L     1
NumChar:       DS.L     1
NumRows:       DS.L     1
StartAddr:     DS.L     1
Error_Flag:    DS.L     1
Error_Addr:    DS.L     1

ASCIIBuff:     DS.B     80

********************* THATS ALL FOLKS *************************************
   END

