* Stack.Asm
*
*       Written 1/1/87 by C.Heath
*
*       This program may be freely distributed, provided it is not modified
* in any way. If an executable is distributed, use assem and blink 6.7,
* which should result in an executable of 400 bytes.

*       This module replaces the ADOS "Stack" command.  It exactly matches
* the Stack command syntax except it also will print a reasonable error
* message if you use a non-numeric command line.  It also will save
* a disk block, and should run faster because it is smaller than the
* magic 488 byte "icon" file size, and is a single segment instead of two.

*       This is installment two of the "Abolish ADOS Commands" series.
* Collect them all, amaze your friends.

******  Equates and publics     ***************************************

        INCLUDE "exec/types.i"
        INCLUDE "libraries/dos.i"
        INCLUDE "libraries/dosextens.i"

MIN_LIB         set     $1f             ; Library minimum rev level!
ASC_ZERO        set     $30             ; Ascii ZERO
MIN_STACK       set     1600            ; Minimum stack allowed by the
                                        ; ADOS "stack" command

my_str          set     -60             ; Size of string allowed to build

*** NOTE: If you use Manx's assembler V3.30E, substitute "public" for "xref"

xlib    macro
        xref    _LVO\1
        endm

        xlib    OpenLibrary
        xlib    CloseLibrary
        xlib    FindTask

        xlib    Output
        xlib    Write

******  The Program             ***************************************

* NOTE: If you are using Manx's assembler V3.30E, you should uncomment
* the following three lines:

*       entry   .begin
*       public  .begin
*.begin

Start:
        move.l  A0,A2                   ; Register A2 is cmdline henceforth

        move.l  4,a6                    ; ExecBase
        suba.l  A1,A1
        jsr     _LVOFindTask(A6)
        move.l  D0,A3                   ; Process base
        move.l  pr_CLI(A3),D0
         beq.s  BadExit                 ; Not a CLI process. Punt
        asl.l   #2,D0
        move.l  D0,A3                   ; A3 points at CLIStruct henceforth

        lea     DOSName(pc),A1          ; Open DOS.library
        moveq.l #MIN_LIB,d0
        jsr     _LVOOpenLibrary(A6)
        or.l    D0,D0
         beq.s  BadExit                 ; Can't!! Return error value...
        move.l  D0,A6                   ; DOSBase in A6 henceforth

        link    A5,#my_str              ; Need some writeable space in stack

************************************************************************
*
* Check the input arguements
*       If there is no arg, print the old stack value
*       Else If the arg is a valid number input, set new stack
*       Else print error message
*
************************************************************************

        move.b  (A2),D0
         beq.s  Do_OldStack
        cmp.b   #$0a,D0
         beq.s  Do_OldStack             ; No command line, print old stack

*
* Here, loop to get input for new stack
* Loop getting Ascii digits
*
        moveq.l #0,D0                   ; New Stack Value built into D0
ll0:    moveq.l #0,D1
        move.b  (A2)+,D1
        cmp.b   #$0A,D1
         beq.s  eos
        sub.b   #'0',D1
         blt.s  bad_input               ; Test for valid digits
        cmp.b   #9,D1
         bgt.s  bad_input

        add.l   D0,D0
        move.l  D0,D2                   ; Multiply prior value by 10
        asl.l   #2,D2                   ; Required to allow long_word value
        add.l   D2,D0

        add.l   D1,D0                   ; Add in new digit
        bra.s   ll0                     ; Loop on digits

* End of string, register D0 is new stack value in bytes
eos:
        cmp.l   #MIN_STACK,D0
         blt.s  too_small                       ; Match "stack" command

        lsr.l   #2,D0                           ; Convert to LWords
        move.l  D0,cli_DefaultStack(A3)         ; Save it and
        bra.s   finished                        ; Get Outa Here!

* Bad input string.  Print error message
bad_input:
        lea     bad_str(pc),A0
        bra.s   ok_print

* Input value too small. Must match ADOS's requirements, ick.
too_small:
        lea     str_too_small(pc),A0
        bra.s   ok_print

************************************************************************
*
* BadExit is where to go if there is an error opening the DOS library
*       This should only happen if things are really sick
*
************************************************************************

BadExit:        moveq   #20,D0
                rts

* No input value, print out the current default stack setting instead
Do_OldStack:

        move.l  cli_DefaultStack(A3),D0
        asl.l   #2,D0                   ; Get current size

        lea     SStr(pc),A1             ; Copy the string to stack area
        lea     my_str(A5),A0
llz:    move.b  (A1)+,(A0)+
         bne.s  llz
        subq    #1,A0                   ; Build string HERE

        lea     divtab(pc),A1           ; Sucessive subtraction table here

ll1:    move.l  (A1)+,D1
        cmp.l   D1,D0
         blt.s  ll1                     ; Find first digit

ll2:    moveq   #ASC_ZERO,D2            ; Loop to calculate this digit
ll3:    cmp.l   D1,D0
         blt.s  ll4
        addq    #1,D2
        sub.l   D1,D0
        bra.s   ll3

ll4:    move.b  D2,(A0)+                ; Output this digit
        move.l  (A1)+,D1                ; Continue to next until
         bne.s  ll2                     ; There Ain't No More

outahere:
        lea     ZStr(pc),A1             ; Copy the "bytes" too
ll5:    move.b  (a1)+,(A0)+
         bne.s  ll5

        lea     my_str(A5),A0           ; Get string origin

***************************************************************************
*
* Here, Write the string at A0, which is null terminated.
*
***************************************************************************
ok_print:
        move.l  A0,D2                   ; Set pointer in D2 for Write arg
        moveq.l #-1,D3
llx:    addq.l  #1,D3                   ; Get length in D3
        tst.b   (A0)+
         bne.s  llx

        jsr     _LVOOutput(A6)          ; Get Output handle
        move.l  D0,D1                   ; It's a calling arg
        jsr     _LVOWrite(A6)           ; Echo "String"

finished:
        move.l  A6,A1
        move.l  4,A6                    ; AbsExecBase
        jsr     _LVOCloseLibrary(A6)

        moveq   #0,D0                   ; Exit(0)
        unlk    A5
        rts


***************************************************************************
*
* Following is just constant data used by the prgram
*
***************************************************************************

divtab:         dc.l    10000000,1000000,100000,10000,1000,100,10,1,0

DOSName:        dc.b    'dos.library',0

str_too_small:  dc.b    'suggested stack size too small',$0a,0
bad_str:        dc.b    'Bad command line. Use "stack #"',$0a,0

SStr:           dc.b    'current stack size is ',0
ZStr:           dc.b    ' bytes',$0a,0

        END
