*****************************************************************************
*
* RemLib.asm	by	HEIKO RATH 
*
*			Copyrigth 1988 by the Software Brewery
*
* This program may be non-commercially distributed.
*
* The purpose of this program is to remove a library from the librarylist.
* To be save, it only removes librarys with an OpenCnt of 0.
* To get a list of all librarys use RemLib without an argument.
*								Heiko Rath
*
*****************************************************************************
*                          
*______  /          
*______\O                    - The Software Brewery - 
*      \\              		    
*       o            Sparkling, fresh software from W.-Germany
*                 
*     @@@@@	      Straight from the bar to your system
*     |~~~|\        
*     | | |/        
*     |___|        With our regards to the Software Distillery
*
*Members are (listed alphabetically):
*Christian Balzer alias <CB>, Lattice C, user interfaces, beer addict. 
*Christof Bonnkirch, Aztec C, telecommunications, beer adict.
*Heiko Rath alias <HR>, Assembler, ROM-Kernal stuff, Marabou chocolate addict. 
*Peter Stark alias PS, Lattice C, IO & utilities, WordStar addict.
*Ralf Woitinas alias RAF, Assembler, anything, Ray-Tracing addict.
*
*Beverages: Altenmuenster Brauer Bier, Urfraenkisches Landbier, Grohe Bock.
*
*Send exotic drinks, beautyfull girls, $$$$, comments, critizism, flames, mail to:
*
*The Software Brewery
*Christian Balzer
*Im Wingertsberg 45
*D-6108 Weiterstadt
*West-Germany
*
*Send the above stuff and of course MARABOU-CHOCOLATE to:
*
*Heiko Rath (AAAARRRRGGGHHH, where is my Marabou chocolate??)
*Raiffeisenstr.10a
*D-6108 Weiterstadt
*Tel.06150-2658
*West-Germany
*
*
*Our BBS "AmigaNode" isn't online yet. As soon as it becomes available, 
*you'll be the first to know :-).
*

ExecBase	Equ	4

***
*** Exec Offsets:
***
OpenLibrary	Equ	-552		;OpenLibrary (LibName,version)(a1,d0)
CloseLibrary	Equ	-414		;CloseLibrary (Library)(a1)
Forbid		Equ	-132		;Forbid ()()
Permit		Equ	-138		;Permit ()()
AllocMem	Equ	-198		;AllocMem (bytesize,requirement)(d0,d1)
FreeMem		Equ	-210		;FreeMem (memoryblock,bytesize)(a1,d0)
FindName	Equ	-276		;FindName (list,name) (a0,a1)
RemLibrary	Equ	-402		;RemLibrary (library)(a1)


***
*** DOS Offsets:
***
OutPut		Equ	-60		;OutPut ()
Write		Equ	-48		;Write (file,buffer,length)(d1,d2,d3)

***
*** I use these Macros to make things easier for me
***

doit:	MACRO
	move.l	#HeadLine,d2		;address of HeadLine to d2
	bsr	TextOutPut		;output HeadLine
	move.l	\1,d0			;offset of listhead to d0
	bsr	Showlib			;output library-list
	ENDM

***
*** Here we go:
***
	move.l	sp,d6			;store stack pointer on stack
	move.l	a0,a2			;save cmdline address
	sub.w	#1,d0
	clr.b	0(a2,d0.w)		;make the cmdline null terminated

	move.l	ExecBase,a6		;Execaddress to a6 (only to be sure)
	move.l	#DOSNAME,a1		;Librarynamepointer to a1
	moveq	#0,d0			;any version
	jsr	OpenLibrary(a6)		;try to open DOS-Libary
	tst.l	d0			;is d0 = NULL?
	beq	ErrorExit		;exit if call wasn't successfull
	move.l	d0,DOSBase		;save DOSBasepointer
	move.l	d0,a6			;move DOSBasepointer to a6
	jsr	OutPut(a6)		;identify the initial output handle
	move.l	d0,stdout		;save stdout

	move.l	#Text,d2
	bsr	TextOutPut

SkipSP:	
	move.b	(a2)+,d1		;skip spaces
	beq.b	ShowTheLibs		;if NULL-String then /* show librarys */
	cmp.b	#' ',d1			;is it a Space ?
	beq.b	SkipSP			;yes -> SkipSP

	cmp.b	#'?',d1			;is it '?' ?
	beq	ShowHow			;yes -> ShowHow

	cmp.b	#'"',d1			;is it '"' ?
	bne.b	001$			;yes -> 001$
	add.l	#1,a2
	move.l	a2,a1
002$:
	move.b	(a1)+,d1
	beq	NoSuchLibrary
	cmp.b	#'"',d1
	beq.b	003$
	bra.b	002$
003$:
	sub.l	#1,a1
	move.b	#0,(a1)
001$:
	sub.l	#1,a2			;decrement address by one
	move.l	ExecBase,a6		;ExecBase to a6
	move.l	a6,a0			;ExecBase to a0
	add.l	liblist,a0		;address of librarylist to a0
	move.l	a2,a1			;address of string to a1
	jsr	FindName(a6)		;search for the given name
	tst.l	d0			;is there a library with the given name

	beq.b	NoSuchLibrary		;no -> NoSuchLibrary

	move.l	d0,a1			;copy address of library to a1
	move.w	32(a1),d0		;get OpenCnt
	tst.w	d0			;is the OpenCnt = 0?
	bne.b	NotZero			;no -> say that the library is still open
	jsr	RemLibrary(a6)		;try to close the library
	tst.l	d0
	bne.b	ShowTheLibs		;->ShowTheLibs

	move.l	#FailedToRemove,d2
	bsr	TextOutPut
	bra.b	ShowTheLibs

NoSuchLibrary:
	move.l	#NotFound,d2
	bsr	TextOutPut
	bra.b	ShowTheLibs

NotZero:
	move.l	#NotAbleToClose,d2
	bsr	TextOutPut

ShowTheLibs:
	doit	liblist			;output Librarylist

CloseDOS:
	move.l	ExecBase,a6		;ExecBase to a6
	move.l	DOSBase,a1		;DOS-pointer to a1
	move.l	ExecBase,a6		;Exec-pointer to a6
	jsr	CloseLibrary(a6)	;close DOS
ErrorExit:
	move.l	d6,sp			;restore stack pointer
	rts				;CLI here we go again!!!!

ShowHow:
	move.l	#HelpText,d2
	bsr	TextOutPut
	bra	ShowTheLibs

*****************************************************************************
*
*	Showlib II					11.1.87
*			by	Heiko Rath
*				Raiffeisenstr.10a
*				D-6108 Weiterstadt
*				West-Germany
*				Tel.06150-2658
*______  /          
*______\O                    - The Software Brewery - 
*      \\              		    
*       o            Sparkling, fresh software from W.-Germany
*                 
*     @@@@@	      Straight from the bar to your system
*     |~~~|\        
*     | | |/        
*     |___|        With our regards to the Software Distillery
*
* Members are (listed alphabetically):
* Christian Balzer alias <CB>, Lattice C, user interfaces, beer addict. 
* Christof Bonnkirch, Aztec C, telecommunications, money adict.
* Heiko Rath alias <HR>, Assembler, ROM-Kernal stuff, Marabou chocolate addict. 
* Peter Stark alias PS, Lattice C, IO & utilities, WordStar addict.
* Ralf Woitinas alias RAF, Assembler, anything, Ray-Tracing addict.
*
* Beverages: Altenmuenster Brauer Bier, Urfraenkisches Landbier, Grohe Bock.
*
*
* PURPOSE:			print out Librarylist (address of Node,
*				type, priority, name of Node, version, revision,
*				opencount)
*
* ROUTINETYPE:			subroutine
*
* SYNTAX:			bsr Showlib	(Exec-offset to librarylist)(d0)
*
* ENTRY CONDITIONS:		needs DOSlibrary opened and stdout defined
*				also needs DOS-'Write' offset -48 defined.
*				It also needs binhex subroutine.
*
* RETURNS:			none
*
* BUGS:			none
*
* NOTE:			none
*
* CHANGED:			nothing
*
* USAGE:			move.l	LibraryListOffset,d0
*				bsr	Showlib
*
*****************************************************************************
Showlib:
	movem.l	d0-d7/a0-a6,-(sp)	;save registers

	move.l	ExecBase,a6		;ExecBase to a6
	jsr	Forbid(a6)		;forbid taskswitching (very important,
					; 'cause we are accessing Systemdata)

	move.l	a6,a0			;Execpointer to a0
	add.l	d0,a0			; + librarylistoffset=address of listhead
	move.l	a0,ListHead		;save address of listheader -=> ListHead
	move.l	(a0),a1			;get address of 1.Node to a1
	move.l	a1,Node			;save address of 1.Node -=> Node
	addq.l	#4,a0
	cmp.l	a1,a0			;list empty?
					;(test if listhead points to listhead+4)
	beq	PrintLF			;yes -=> send LF and exit

	moveq.l	#1,d1			;set counter to 1 'cause there is at least
					; one node in the list
MyCountLoop:
	move.l	(a1),a1			;get address of next node to a1
	tst.l	(a1)			;see if contents of (a1) is NULL
	beq.b	EndCount		;leave counting loop
	addq.l	#1,d1			;increment counter by one
	bra.b	MyCountLoop		;do this once more

EndCount:
	move.l	d1,NodeCount		;save number of Nodes

	move.l	#58,d0			;number of bytes per node
	mulu	d1,d0			;bytes per node * NodeCount
	addq.l	#1,d0			;add one for the bufferterminating Null
	move.l	d0,MyMemoryLength	;save lenght of Memoryblock
	move.l	#$10001,d1		;requirements:MEMF_Public & Clear
	jsr	AllocMem(a6)		;get memory from system
	move.l	d0,MyMemoryBlock	;save address of Memoryblock
	move.l	d0,MyMemoryOffset	;save address of Memoryblock 2.time
	tst.l	d0			;see if call was successfull
	bne	MoveNodeToBuffer	;yes -=> MoveNodeToBuffer

	move.l	#Err,d2			;this code is only here, to inform the
	bsr	TextOutPut		; user that the AllocMem call wasn't
	bra	PrintLF			; successfull

MoveNodeToBuffer:
	move.l	d0,a0			;get address of MemoryBlock to a0
	move.l	MyMemoryLength,d1	;get length to d1

fill:
	move.b	#' ',(a0)+		;fill MyMemoryBlock with spaces
	dbeq.b	d1,fill			;is d1=NULL? (no-=>d1=d1-1-=>fill)

TheLoop:
	move.l	MyMemoryOffset,a0	;get address of MyMemoryOffset to a0
	move.l	Node,a1			;get address of current node to a1

	add.l	#10,a1			;address of namepointer to a1
	move.l	(a1),a1			;get address of nodename to a1
	moveq.l	#0,d1			;this is faster than clr.l d1
	moveq.l	#0,d2			;set this to NULL for strlen

strlen:
	cmp.b	(a1)+,d2		;NULL?
	beq.b	strlentest		;yes -=>strlentest
	addq.l	#1,d1			;increment d1 by one (stringlength)
	bra.b	strlen			;do the loop once more

strlentest:
	cmp.b	#20,d1			;see if string is greater #20
	ble.b	DoCopy			;no (less or equal)-=>DoCopy
	move.l	#20,d1			;set max.length to 20

DoCopy:
	move.l	Node,a1			;get address of node to a1
	add.l	#10,a1			;address of namepointer to a1
	move.l	(a1),a1			;get address of nodename to a1
	tst.l	d1			;see if d1=0
	bne	DoTheCopy		;jump only if d1<>0
	move.l	#NoName,a1		;get address of NoName to a1
	moveq.l	#7,d1			;set length to 7 (length of 'No Name')

DoTheCopy:
	subq.l	#1,d1			;decrement d1 by 1

CopyLoop:
	move.b	0(a1,d1),0(a0,d1)	;copy source to destination
	dbf	d1,CopyLoop		;decrement d1, if d1<0 then out of loop

	move.l	MyMemoryOffset,a0	;get address of MyMemoryOffset to a0
	move.b	#'$',21(a0)		;store '$'
	move.b	#'$',35(a0)		;store '$'
	move.b	#10,57(a0)		;store LF

	move.l	Node,a1			;get Nodeaddress to a1
	addq.l	#8,a1			;add 8 to get address of Type
	moveq.l	#0,d0			;clear d0
	move.b	(a1),d0			;get Type to d0
	move.l	MyMemoryOffset,a0
	add.l	#31,a0
	bsr	bindecb			;convert to ASCII

	move.l	Node,a1			;get Nodeaddress to a1
	add.l	#9,a1			;add 1 to get address of Priority
	moveq.l	#0,d0
	move.b	(a1),d0
	move.l	MyMemoryOffset,a0
	add.l	#35,a0
	bsr	bindecb

	move.l	Node,a1			;get Nodeaddress to a1
	add.l	#32,a1			;add 32 to get address of OpenCnt
	moveq.l	#0,d0			;clear d0
	move.w	(a1),d0			;get OpenCnt to d0
	move.l	MyMemoryOffset,a0
	add.l	#39,a0
	bsr	bindecw			;convert OpenCnt to ASCII

	move.l	Node,a1			;get Nodeaddress to a1
	add.l	#20,a1
	moveq.l	#0,d0
	move.w	(a1),d0			;Version
	move.l	MyMemoryOffset,a0
	add.l	#45,a0
	bsr	bindecw

	move.l	Node,a1
	add.l	#22,a1
	moveq.l	#0,d0
	move.w	(a1),d0			;Revision
	move.l	MyMemoryOffset,a0
	add.l	#51,a0
	bsr	bindecw

	move.l	Node,d0			;get Nodeaddress to d2
	move.l	MyMemoryOffset,a0	;get address of MyMemoryOffset to a0
	add.l	#22,a0			;add 22 to get storeaddress
	bsr	binhex			;convert address to ASCII

	add.l	#58,MyMemoryOffset	;do this for the next loop
	move.l	Node,a1			;get nodeaddress to a1
	move.l	(a1),Node		;save address of next node
	move.l	MyMemoryOffset,d0	;get MyMemoryOffset to d0
	addq.l	#1,d0
	move.l	MyMemoryBlock,d1	;get MyMemoryBlock to d1
	add.l	MyMemoryLength,d1	;add MyMemoryLength to d1
	cmp.l	d0,d1			;see if we have to loop once more
	bne	TheLoop			;if <> -=> TheLoop
	move.l	MyMemoryBlock,a0	;get address of MyMemoryBlock to a0
	add.l	MyMemoryLength,a0	;add length to MyMemoryBlock
	subq.l	#1,a0			;decrement address by one
	move.b	#0,(a0)			;set last byte of MyMemoryBlock to NULL

	move.l	MyMemoryBlock,d2	;get address of MyMemoryBlock to d2
	bsr	TextOutPut		;print out the complete buffered list
	move.l	MyMemoryBlock,a1	;get address of MyMemoryBlock to a1
	move.l	MyMemoryLength,d0	;get length of MyMemoryBlock to d0
	jsr	FreeMem(a6)		;free the allocated RAM

PrintLF:
	move.l	#LF,d2			;get address of LF-string to d2
	bsr.b	TextOutPut		;and get it out via DOS-Write & stdout
	jsr	Permit(a6)		;permit taskswitching (I think Dos enables
					; this for you, but I do this to be sure
					; that taskswitching is now allowed.)
	movem.l	(sp)+,d0-d7/a0-a6	;restore Registers
	rts

*****************************************************************************
*
*	TextOutPut
*			by	Heiko Rath
*				Raiffeisenstr.10a
*				D-6108 Weiterstadt
*				West Germany
*				Tel.06150-2658
*______  /          
*______\O                    - The Software Brewery - 
*      \\              		    
*       o            Sparkling, fresh software from W.-Germany
*                 
*     @@@@@	      Straight from the bar to your system
*     |~~~|\        
*     | | |/        
*     |___|        With our regards to the Software Distillery
*
* Members are (listed alphabetically):
* Christian Balzer alias <CB>, Lattice C, user interfaces, beer addict. 
* Christof Bonnkirch, Aztec C, telecommunications, beer adict.
* Heiko Rath alias <HR>, Assembler, ROM-Kernal stuff, Marabou chocolate addict. 
* Peter Stark alias PS, Lattice C, IO & utilities, WordStar addict.
* Ralf Woitinas alias RAF, Assembler, anything, Ray-Tracing addict.
*
* Beverages: Altenmuenster Brauer Bier, Urfraenkisches Landbier, Grohe Bock.
*
* PURPOSE: 		output a NULL-terminated string via stdout
*
* ROUTINE TYPE: 	subroutine
*
* SYNTAX:		bsr	TextOutPut	(stringaddress)(d0)
*
* ENTRY CONDITIONS:	needs DOSlibrary opened and stdout defined
*			also needs DOS-'Write' offset -48 defined.
*
* RETURNS:		none
*
* NOTE:		its better if the string is really NULL-terminated
*
* CHANGED:		nothing
*
* USAGE:		move.l	#Textaddress,d2
*			bsr	TextOutPut
*
*****************************************************************************

TextOutPut:
	movem.l	d0-d7/a0-a6,-(sp)	;save registers
	move.l	d2,a0			;address to a0
	clr.l	d3			;count = 0

CountLoop:
	tst.b	(a0)+			;is it NULL ?
	beq.b	PMsg			;yes: -=> determine length
	addq.l	#1,d3			;count = count+1
	bra.b	CountLoop		;test next byte

PMsg:
	move.l	stdout,d1		;get stdout to d1
	move.l	DOSBase,a6		;move DOSBase to a6
	jsr	Write(a6)		;write the Text
	movem.l	(sp)+,d0-d7/a0-a6	;reserve registers
	rts

***********************************************************************
*
*	 binhex
*		 	by Heiko Rath
*
* PURPOSE: Convert a binary value in a register to
*	    a hex ASCII string at the destination address
*          
* ROUTINE TYPE: SUBROUTINE
*
* SYNTAX: bsr	binhex	(source(long),destination) (d0.l,a0)
*	   bsr	binhexw	(source(word),destination) (d0.w,a0)
*	   bsr	binhexb	(source(byte),destination) (d0.b,a0)
*
* ENTRY CONDITIONS: None
*
* RETURNS: ASCII string in destination address
* NOTE: 	the destination place must contain 8 bytes for any
*	        length (byte, word, longword)
*
* CHANGED: Nothing
*
* USAGE:
*
*	 move	#label,d0
*	 move.l	address,a0	;converts the address at label to
*	 bsr	binhex		;string at address
*				
*	 move	label,d0
*	 move.l	address,a0
*	 bsr	binhex		;conv contents at label
*
*	 move	#value,d0
*	 move.l	address,a0
*	 bsr	binhex		;convert immediate value
*
****************************************************************

binhex:	movem.l	d0-d2/a0,-(sp)		;save registers

	move.l	#7,d2			;get number of counts to d2
	clr.l	d1			;clear work register

001$:	rol.l	#4,d0			;move high nibble to low order
	move.b	d0,d1			;get low order byte to d1
	andi.b	#$f,d1			;isolate low order nibble
	cmp.b	#$0a,d1			;is it a letter or a digit?
	blt.b	002$			;if digit -=> 002$
	add.b	#'A'-'0'-$0A,d1		;offset for letters

002$:	add.b	#'0',d1			;convert to ASCII
	move.b	d1,(a0)+		;store it and increment storeaddress
	dbf.b	d2,001$			;do the converting 8 times

	movem.l	(sp)+,d0-d2/a0		;restore registers
	rts

***********************************************************************
*
*	 bindec
*		 	by Heiko Rath
*
* PURPOSE: Convert a binary value in a register to
*	    a dec ASCII string at the destination address
*          
* ROUTINE TYPE: SUBROUTINE
*
* SYNTAX:
*	   bsr	bindecw	(source(word),destination) (d0.w,a0)
*	   bsr	bindecb	(source(byte),destination) (d0.b,a0)
*
* ENTRY CONDITIONS: None
*
* RETURNS: ASCII string in destination address
* NOTE: 	the destination place must contain 5 bytes for any
*	        length (byte, word). Don't use longwords!
*
* CHANGED: Nothing
*
* USAGE:
*
*	 move	#label,d0
*	 move.l	address,a0	;converts the address at label to
*	 bsr	bindec		;string at address
*				
*	 move	label,d0
*	 move.l	address,a0
*	 bsr	bindec		;conv contents at label
*
*	 move	#value,d0
*	 move.l	address,a0
*	 bsr	bindec		;convert immediate value
*
****************************************************************

bindecb:
	movem.l	d0-d2/a0,-(sp)		;store registers
	move.l	d0,d1
	move.l	a0,a1
	bra.b	ByteToDec

bindecw:
	movem.l	d0-d2/a0,-(sp)		;save registers
	move.l	d0,d1
	move.l	a0,a1

	divu	#10000,d1
	bsr.b	StoreOneByte
	divu	#1000,d1
	bsr.b	StoreOneByte
ByteToDec:
	divu	#100,d1
	bsr.b	StoreOneByte
	divu	#10,d1
	bsr.b	StoreOneByte
	bsr.b	StoreOneByte

003$:					;003$ is used to clear the
	move.b	(a1)+,d0		; leading zeros
	cmp.b	#'0',d0
	bne.b	002$
	cmp.b	#' ',(a1)
	beq.b	002$
	move.b	#' ',-(a1)
	add.l	#1,a1
	bra.b	003$
002$:
	movem.l	(sp)+,d0-d2/a0		;restore registers
	rts

StoreOneByte:
	add.b	#$30,d1
	move.b	d1,(a0)+
	clr.w	d1
	swap	d1
	rts

***
*** Variables:
***

DOSBase:	dc.l	0		;this contains the DOSlibraryaddress
stdout:		dc.l	0		;this contains stdout
					; address of the cmdline
ListHead:
	dc.l	0			;At runtime this contains the
					; address of the listheader
Node:
	dc.l	0			;At runtime this contains the
					; address of the current node
NodeCount:
	dc.l	0			;At runtime this contains the
					; number of nodes in the list
MyMemoryLength:
	dc.l	0			;At runtime this contains the
					; length of the memoryblock
MyMemoryBlock:
	dc.l	0			;At runtime this contains the
					; address of the memoryblock
MyMemoryOffset:
	dc.l	0			;At runtime this contains the
					; address of the memoryblock
					; + 48 Bytes per finished node

***
***Constants:
***
liblist:	dc.l	$17a

DOSNAME:	cstring	'dos.library'
		cnop	0,2
Err:		dc.b	'*** Out of Memory Error ***',0
		cnop	0,2
NoName:		dc.b	'No Name',0
		cnop	0,2
LF:		dc.b	10,0		;LF
		cnop	0,2
HeadLine:	dc.b	$9b,'4;32;40m'
		dc.b	'Name                  Address  Typ Pri OpenC Vers. Revis.'
		dc.b	$9b,'0;31;40m',10,0
		cnop	0,2
Text:
	dc.b	$9b,'0;33;40m','Lib-Remover',$9b,'0;31;40m'
	dc.b	'  by ',$9b,'0;32;40m','Heiko Rath',$9b,'0;31;40m',' - '
	dc.b	$9b,'4;31;40m',169,' by ',$9b,'1;31;40m'
	dc.b	'The Software Brewery',$9b,'0;31;40m',10
	dc.b	'Raiffeisenstr.10a, D-6108 Weiterstadt, Tel. 06150-2658',10
	dc.b	0

	cnop	0,2
NotAbleToClose:
	dc.b	$9b,'0;33;40m','Attention:',$9b,'0;31;40m'
	dc.b	' This library can not be closed, cause OpenCnt > 0',10,0
	cnop	0,2
FailedToRemove:
	dc.b	$9b,'0;33;40m','Attention:',$9b,'0;31;40m'
	dc.b	' Failed to remove the library',10,0
	cnop	0,2
NotFound:
	dc.b	$9b,'0;33;40m','Attention:',$9b,'0;31;40m'
	dc.b	' Library not found',10,0
	cnop	0,2
HelpText:
	dc.b	'Use ',$9b,'0;33;40m','Remlib',$9b,'0;31;40m'
	dc.b	' ',34,'name.library',34,' to remove a library',10,0
