; ; Break.asm ; ; Written: Jan/7/1987 by SDB ; ; This program may be freely distributed. Improvements are welcome, ; but any code based on this program can never become proprietary. ; You are welcome to use, improve, and distribute this program. ; You are forbidden to prevent anyone else from using, improving, ; or distributing this program. ; ; This is a contribution to Cheath's Abolish ADOS Commands series. ; Let's get them all done, and boogie! ; ; I have only assembled this with the old Manx assembler, it comes ; in at 488 bytes. The Metacompost assembler should shave about 72 ; bytes or so off of that. (The BCPL Break is 980 bytes in size). ; ; Syntax is the same as the old break, except you don't need to ; put spaces between the flags: ; ; Break 4 c d e f ; Break 4 cdef ; ; work the same. ; ; Register usage: ; a6 - Current Lib base we need (exec or dos) ; a5 - storage for DOSBase ; a2 - pointer to task array ; a0 - pointer to next character of command line. ; d2 - task number to signal ; d3 - signals to send to task. ; a2 - pointer to task array ; ; all others, pretty much scratch as scratch can. ; _LVOOpenLibrary equ -552 _LVOCloseLibrary equ -414 _LVOForbid equ -132 _LVOPermit equ -138 _LVOSignal equ -324 _AbsExecBase equ 4 _LVOOutput equ -60 _LVOWrite equ -48 dl_Root equ 34 TASK_SIZE equ 92 LIBRARY_VERSION equ 31 ; Don't need anything higher. uselen equ 49 ; length of How To Use message tasklen equ 26 ; length of You Screwed Up message ; SIGBREAKF_CNTRL_C equ $1000 ; Default signal == ^C SIGBREAKF_ALL equ $f000 ; Send all signals. ; ; ; Need the following entry and rts for manx assembler/linker. ; entry Start rts Start: move.l a0,-(sp) move.l _AbsExecBase,a6 lea DOSName(pc),a1 moveq.l #LIBRARY_VERSION,d0 jsr _LVOOpenLibrary(a6) tst.l d0 bne.s good addq.w #4,sp ; Things are bad. No dos. move.l #20,d0 rts good: move.l d0,a5 ; keep dos pointer here for now moveq.l #0,d2 ; zero target_task move.l d2,d3 ; zero target_signals move.l (sp)+,a0 lex: bsr.s getnxt ; get upper case char in d0 cmp.b #'F',d0 ; characters greater than F are never valid bhi.s usage ; so gently explain how to use. cmp.b #' ',d0 beq.s lex ; skip blanks cmp.b #$0a,d0 ; check for eol bne.s cntrlp tst.l d2 ; Check args - if d2 is still zero, then beq.s usage ; Send'em a how to message. bra.s doit getnxt: ; return an upper case character moveq.l #0,d0 ; clear move.b (a0)+,d0 cmp.b #'a',d0 bcs.s getrts and.b #$5f,d0 getrts: rts cntrlp: cmp.b #'A',d0 ; if one of C D E or F, calculate the bls.s allp ; value of the signal to send the tas k. sub.b #$37,d0 ; get the bit number moveq.l #1,d1 asl.l d0,d1 ; get the mask or.l d1,d3 ; add to current signals bra.s lex allp: cmp.b #'A',d0 ; All flags? bne.s digitp bsr.s getnxt cmp.b #'L',d0 bne.s usage bsr.s getnxt cmp.b #'L',d0 bne.s usage found: move.l #SIGBREAKF_ALL,d3 ; set all flags bra lex digitp: ; must be a numeric... tst.l d2 ; but only one per customer bne.s usage ; or syntax error (can only signal one task) dodigit: sub.b #'0',d0 blt.s usage cmp.b #9,d0 bgt.s usage add.l d2,d2 move.l d2,d1 asl.l #2,d1 add.l d1,d2 add.l d0,d2 bsr.s getnxt cmp.b #' ',d0 beq.s lex cmp.b #$0a,d0 bne.s dodigit doit: tst.l d3 ; check target signals bne.s sigsok move.l #SIGBREAKF_CNTRL_C,d3 ; If no flags, set default. sigsok: move.l _AbsExecBase,a6 jsr _LVOForbid(a6) move.l dl_Root(a5),a1 move.l (a1),a2 ; BPTR to task array move.l a2,d0 asl.l #2,d0 move.l d0,a2 ; pointer to task array -- check for errors cmp.l (a2),d2 ; Task# can't be outside of taskarray bounds bge.s task_error tst.l d2 beq.s task_error ; task can't be zero. (Have to check here asl.l #2,d2 ; as well as in lex routines.) move.l 0(a2,d2.l),d0 ; or non-existant beq.s task_error ; ; task now holds pointer to msg port of task ; subtract #bytes in a tcb to get the actual address of the task ; for signal. ; move.l d0,a1 sub.l #TASK_SIZE,a1 ; ; now send the signals to our task. ; move.l d3,d0 jsr _LVOSignal(a6) jsr _LVOPermit(a6) clr.l -(sp) bra.s bye ; exit(0) ; ; Error Handlers ; ; Usage - just tell folks how to use, and beat it. ; usage: lea usemsg(pc),a0 move.l #uselen,d3 moveq #0,d0 bra.s write_it ; ; task_error - Call this when user tries to signal a non-existant task. ; task_error: jsr _LVOPermit(a6) ; turn multitasking back on lea taskmsg(pc),a0 move.l #tasklen,d3 move.l #20,d0 ; ; Write the message. Enter with length in d3, strptr in a0, and exit code ; in d0. ; write_it: move.l d0,-(sp) ; save exit code move.l a0,d2 ; put strptr where write expects it move.l a5,a6 ; get DOSBase in a6 jsr _LVOOutput(a6) move.l d0,d1 jsr _LVOWrite(a6) bye: ; common exit for all routines move.l a6,a1 ; except if dos doesn't open move.l _AbsExecBase,a6 jsr _LVOCloseLibrary(a6) move.l (sp)+,d0 rts ; ; data area ; usemsg: dc.b "Usage: Break [ALL] [C] [D] [E] [F]",10 taskmsg: dc.b "That task does not exist.",10 DOSName: dc.b "dos.library",0