;
;
;	*****************
;	*		*
;	*  SECTION.ASM	*
;	*     v1.1	*
;	*		*
;	*****************
;
; 06/27/82 by Ron Fowler, Westland, Michigan
;
; 08/09/83 adapt for CP/M+ by Dick Lieber, Chicago Illinois  312-326-4392
;
; 04/20/84 adapted for CP/M+ with user numbers over 9
;          by James M. Scardelis, Director CP/M Plus Users' Group
;	   P.O. Box 295, Little Falls, NJ 07424-0295
; 
; This program is intended for RCPM systems where
; files are grouped into drive/user area by their
; classification.  This program implements a naming
; convention, whereby a caller can move into a
; section by typing its name, rather than the random
; searching formerly needed.
;
; Syntax is:  SECTION [<section-name>]
;
; If section-name is omitted, a short list of
; available sections is printed. The special
; form "SECTION ?" prints the detailed description
; of each section.
;
; You have to fill in the sections table
; (located near the end of this program) for your
; particular system.
;
;----< Examples of use: >-----
;
; A0>SECTION ATARI	;changes drive/user to atari area
; B4>SECTION MBASIC	;changes drive/user to mbasic area
; A6>SECTION		;prints short list of sections
; A9>SECTION ?		;prints the detailed list
;
false	equ	0	;define truth and falsehood
true	equ	not false
;
; the following equates may be
; customized to your preference
;
autodir equ	1		;run directory command when new drive
				;/user is selected.  Only works with
				;cp/m+ but will be ignored in 2.2
descol	equ	15		;column # where description begins
				;(in detailed list) (should be greater
				;than longest section name) (but small
				;enuf so display is not too long)
perlin	equ	4		;names printed per line in short list
tabpos	equ	8		;tab stops (set mod tabpos)
				;should be at least one greater than
				;longest section name.
turbo	equ	false		;set TRUE if you'er running TurboDOS
;
; o/s conventions
;
cpbase	equ	0		;set to 4200H for Heath
ccpdrv	equ	cpbase+4	;ccp user/drive storage loc
bdos	equ	cpbase+5	;system entry point
dfcb	equ	cpbase+5CH	;default file control block
dbuf	equ	cpbase+80H	;default buffer
tpa	equ	cpbase+100H	;base of transient program area
coninf	equ	1		;system call, get console char
conotf	equ	2		;system call, console output
printf	equ	9		;system call, print cons string
cstsf	equ	11		;system call, get console status
version	equ	12		;system call, return version
setdrv	equ	14		;system call, set/drive system call
getdrv	equ	25		;system call, get drive # system call
gsuser	equ	32		;system call, get/set user number
chain	equ	47		;system call, chain to ccp command (cpm+ only)
;
; character definitions
;
cr	equ	13		;carriage-return code
lf	equ	10		;linefeed code
;
; code begins....
;
	org	tpa
;
;
pbase:	lxi	h,0		;save system stack
	dad	sp
	shld	spsave
	lxi	sp,stack	;load local stack
;
	if	not turbo	;cp/m, get drive #
	mvi	c,getdrv	;get current drive #
	call	bdos
	push	psw		;save it
	sta	newdrv		;two ways
	endif
;
	call	sect		;perform the section function
;
	if	not turbo	;turbodos doesn't need this stuff
	lda	newdrv		;get newly logged drive
	mov	b,a		;save for comparison
	pop	psw		;get old logged drive
	cmp	b		;did logged drive change?
	jnz	cpbase		;then relog with warm boot
	endif
;
	lhld	spsave		;else restore stack
	sphl
	ret			;to system...
;
; scan cmd line...if an arg exists, attempt to
; match it in the table.  If no arg, dump a list
; of available sections.
;
sect:	lda	dfcb+1		;is there a cmd-line arg?
	cpi	' '
	jz	prnqk		;then go print sections out
	cpi	'?'		;wants detailed list?
	jz	prntbl		;then go do it
	lxi	h,dbuf		;something there, scan to it
scanbk: inx	h		;  ignoring blanks
	mov	a,m
	cpi	' '
	jz	scanbk
	lxi	d,table 	;point de to the section table
loop:	push	h		;save cmd line arg pointer
eloop:	ldax	d		;test entry against table
	cpi	1		;end of entry marker?
	jnz	noend		;jump if not
	mov	a,m		;yes, did user cmd terminate also?
	ora	a
	jz	match		;then declare a match
	jmp	nomat		;else declare a mismatch
noend:	cmp	m
	jnz	nomat		;skip if no match
	inx	h		;continue with comparison
	inx	d
	jmp	eloop
;
; here when an entry didn't match
;
nomat:	ldax	d
	ora	a		;entry terminator?
	inx	d
	jnz	nomat		;scan through it
	pop	h		;restore cmd line arg pntr
	inx	d		;end of entry, skip over user #
	inx	d		;and drive
	ldax	d		;end of table?
	ora	a		;(terminated by 0)
	jnz	loop		;go scan another if not
;
; here when no match can be found
;
	lxi	d,matmsg	;print out no-match message
	mvi	c,printf
	call	bdos
	jmp	prnqk		;go give short list
;
; here when a match is found
;
match:	xchg			;hl==> user #
scmat:	inx	h		;scan past description
	mov	a,m		;looking for terminating null
	ora	a
	jnz	scmat
	inx	h		;skip over terminator
	mov	a,m		;fetch user #
	sui	'0'		;subtract ascii bias
	cpi	10		;is it > 9?
	jc	scmat2		;no, so continue on
	sui	7		;remove the rest 
scmat2:	mov	e,a
	inx	h		;point hl to drive #
	push	d		;save user #
	push	h		;and pointer
	mvi	c,gsuser	;set user number
	call	bdos
	pop	h		;restore pointer to drive
	mov	a,m		;fetch drive
	sui	'A'		;subtract ascii bias
	sta	newdrv		;set new logged drive
	pop	d		;restore user number in e
	mov	d,a		;save drive #
	mov	a,e		;fetch user number
	rlc			;rotate to high nybble
	rlc
	rlc
	rlc
	ora	d		;"or" in the drive
	sta	ccpdrv		;save for ccp use
;
;	if	turbo		;if turbodos...
	push	h
	mvi	c,setdrv	;...have to set drive explicitly
	mov	e,d		;get drive in e
	call	bdos		;set the drive
	pop	h
;	endif
;
	pop	d		;clear garbage from stack
;
;	cpm+ stuff  -- setting user/drive at 4 is an undocumented
;		       feature of cp/m 2.2, it has no effect on version 3
;
	push	h
	mvi	c,version
	call	bdos
	mvi	a,30h		;version that supports chain
	cmp	l
	pop	d
	rnc			;all done if not cp/m+
;
;	move user/drive from table to default buffer
; 
	lxi	h,80h
	ldax	d	;get drive
	mov	m,a

	inx	h
	dcx	d
	ldax	d	;get user
	cpi	'A'     ; is it a letter?
	jc	fin
	inx	h	; yes, so move to second position in d/u spec.
	sui	17	; subtract bias
	mov	m,a	; save it
	dcx	h	; go back to first position.
	mvi	a,'1'	; first digit is always a one now.
	mov 	m,a	; put it there
	inx	h	; and set H for next routine
	jmp	fin2	;and do it.

fin:	mov	m,a

fin2:	inx	h
	mvi	m,':'	;to indicate user/drive request
	if	autodir
	inx	h
	mvi	m,'!'	;command seperator
	inx	h
	mvi	m,'D'
	inx	h
	mvi	m,'I'
	inx	h
	mvi	m,'R'
	endif
	inx	h
	mvi	m,0	;mark end of command buffer

	mvi	c,chain
	mvi	e,0		;flag to make current drive/user ccp default
	call	bdos
	

;
; message printed when match failed
;
matmsg: db	cr,lf,'++ Entry not found ++'
	db	cr,lf,cr,lf,'$'
matms2: db	cr,lf,'Type "SECTION ?" for detailed list'
	db	cr,lf,'      of available sections.',cr,lf
	db	cr,lf,'Type "SECTION <section-name>" to log'
	db	cr,lf,'      into a particular section.'
	db	cr,lf,'$'
;
; print "quick list"
;
prnqk:	lxi	d,tblmsg
	mvi	c,printf
	call	bdos
	lxi	h,table 	;print abbreviated list
qloop:	mvi	b,perlin	;get names-per-line counter
qloop2: mov	a,m		;end of table?
	ora	a
	jz	qkend		;then go print end msg
	call	prathl		;else print the name
qscan:	mov	a,m		;scan to description terminator
	inx	h		;(this effectively ignores
	ora	a		; the description)
	jnz	qscan
	inx	h		;skip over user #
	inx	h		;and drive #
	dcr	b		;count down line entry counter
	jnz	qtab		;go tab if line not full
	call	crlf		;else turn up new line
	jmp	qloop		;and continue
;
; tab between entry names
;
qtab:	mvi	a,' '		;seperate names with tabs
	call	type
	lda	column		;get column #
qsub:	sui	tabpos		;test tab position
	jz	qloop2		;continue if at a tab position
	jnc	qsub		;convert mod tabpos
	jmp	qtab		;keep tabbing
;
qkend:	call	crlf		;do newline
	lxi	d,matms2	;print ending message
	mvi	c,printf
	call	bdos
	call	crlf
	ret
;
; here to print out a list of available section numbers
;
prntbl: lxi	d,tblmsg	;print heading message
	mvi	c,printf
	call	bdos
	call	crlf		;turn up new line
	lxi	h,table
prloop: mov	a,m		;end-of-table?
	ora	a
	rz			;then all done
	call	prathl		;print the name
tab:	mvi	a,'.'		;tab over with leader
	call	type
	lda	column		;get column
	cpi	descol		;at description column yet?
	jc	tab		;then keep tabbing
	call	prathl		;print description
	inx	h		;skip over user #
	inx	h		;and drive number
	call	crlf		;turn up new line
	jmp	prloop		;and continue
;
; print message @hl until null or 01 binary
;
prathl: mov	a,m		;fetch char
	inx	h		;point past it
	ora	a		;null?
	rz			;then done
	cpi	1		;1 also terminates
	rz
	call	type		;nope, print it
	call	break		;check for console abort
	jmp	prathl
;
; test for request from console to stop (^C)
;
break:	push	h		;save 'em all
	push	d
	push	b
	mvi	c,cstsf 	;get console sts request
	call	bdos
	ora	a		;anything waiting?
	jz	brback		;exit if not
	mvi	c,coninf	;there, is, get it
	call	bdos
	cpi	'S'-64		;got pause request?
	mvi	c,coninf
	cz	bdos		;then wait for another character
	cpi	'C'-64		;got abort request?
	jz	quit		;then go abort
brback: pop	b		;else restore and return
	pop	d
	pop	h
	ret
;
; request from console to abort
;
quit:	lxi	d,qmesg 	;tell of quit
	mvi	c,printf
	call	bdos
	lhld	spsave		;get stack pointer
	sphl
	ret
;
qmesg:	db	cr,lf,'++ Aborted ++',cr,lf,'$'
;
; turn up a new line on display
;
crlf:	mvi	a,cr		;print a return
	call	type
	mvi	a,lf		;get lf, fall into type
;
; Routine to print char in A on console,
; while maintaining column number. 
;
type:	push	h		;save everybody
	push	d
	push	b
	mov	e,a		;align char for printing
	push	psw		;save char
	mvi	c,conotf
	call	bdos		;print it
	pop	psw		;restore char
	lxi	h,column	;bump column counter
	cpi	lf		;linefeed doesn't chang column
	jz	nochg
	inr	m
	cpi	cr		;carriage-return zeroes it
	jnz	nochg		;skip if not cr
	mvi	m,0		;is, zero column
nochg:	pop	b		;restore & return
	pop	d
	pop	h
	ret
;
; dump heading message
;
tblmsg: db	cr,lf,'Available sections are:',cr,lf,'$'

;
;
; variables
;
spsave: dw	0		;stack-pointer save
column: db	0		;current column #
newdrv: db	0		;new drive # to log
	ds	20		;the stack
;
stack	equ	$		;define it
;
;
;
;
; SECTIONS TABLE (located at end for easy patching with DDT)
;
; This is the table that defines the sections.	Entry format is:
;
;	<name>,sep,<description>,null,user,drive
;
; where <name>	       is the section name
;	sep	       is a binary 1 used to terminate the match test
;	<description>  is a one-line-or-less comment printed when
;		       the list is dumped.  Match testing terminates
;		       before this field.
;	null	       is a binary 0 used to terminate the description
;	user	       is the user number (0-15) of the section (ascii)
;	drive	       is the drive (A-P) number of the section (ascii)
;
; the table ends with a <name> of zero (binary).
;
; Note: be sure to make section names ALL-CAPS, because the
;	CCP converts command-line arguments to capitals. The
;	description may be in lower case, since it has nothing
;	to do with the matching process.
; Also: although the drive and user # is in ascii (for convenience
;	in setting up the table), be sure to use caps for the
;	drive designation.  No error checking is done on the values.
;
table:	DB	'ARCHIVE',1,'Archives - .LBR files',0,'1A'
	db	'ASSEM',1,'Assembly Language Sources',0,'3B'
	db	'BASIC',1,'BASIC Language Sources',0,'5B'
	db	'BIOS',1,'This system''s BIOS',0,'FB'
	db	'C',1,'C Language Sources',0,'9B'
	db	'CPPLUG',1,'CP/M Plus User''s Group Library - .LBR Files',0,'7B'
	db	'DBASE',1,'dBase II Sources and Database',0,'6B'
	db	'DOCS',1,'Documentation - .LBR Files',0,'8B'
	db	'GAMES',1,'Games - .LBR Files',0,'4B'
	db	'HDUTIL',1,'Hard Disk Utilities',0,'FA'
	db	'OTHER',1,'Whatever fails classification',0,'BB'
	db	'PASCAL',1,'PASCAL Language Sources',0,'2B'
	db	'PL/I',1,'PL/I Language Sources',0,'1B'
	db	'SYSTEMA',1,'System Files - No Access',0,'0A'
	db	'SYSTEMB',1,'System Files - No Access',0,'0B'
	db	'UPLOADS',1,'Recently Uploaded Software',0,'AB'
	db	0		;<<== end of table
;
; -----< end of SECTIONS table>-----
;
	end	pbase		;that's all.
