version	equ	12
;************************************************
;						*
;	<<<  Flags Editor  >>>			*
;						*
;		by Dick Lieber			*
;		   comment at 312-326-4014	*
;		   or via Chicago CBBS		*
;						*
;		11/7/81				*
;						*
;11/14/81 Screen functions generalized, f1, f2	*
;	  attributes corrected. (C. Strom)	*
;************************************************
;							
no	equ	0
yes	equ	not no
;
	org	100h
;********************************************************
;	<<< This must be configured for	 >>>		*
;	<<< your own terminal parameters >>>		*
;							*
lineeded equ	yes	;yes if term needs lead-in	*
lichar	equ	126	;lead in char for your term	*
clrchar	equ	28 	;clear screen character		*
;			;modify for your terminal	*
;
homeimp	 equ	yes	;yes if you have a home cursor	*
;			;character.  lineeded applies.	*
;			;clrchar is used if no		*
homechar equ	18	;character to home cursor	*
;							*
;********************************************************

bdos	equ	05H
deffcb	equ	5CH		;used for inital search
dmarea	equ	80H		;used only
filenamlen equ	0CH
ptextlength equ	10H		;length of each flag descriptor
combuflen equ	16

cr	equ	0dh
bs	equ	8
ctlu	equ	15h		;key to press to update flags
esc	equ	1bh
;
;	bdos commands
;
conin	equ	1
conout	equ	2	
prstr	equ	9
readbuff equ	10
searchf	equ	17
setattr	equ	30
;
;	saveold and setup private stack
;
	lxi	h,0
	dad	sp
	shld	oldstack
	lxi	sp,stacktop
;
	call	inlnprt
	db	'Set  & Display file flags'
	db	0dh,0ah
	db	'Version '
	db	version/10 + '0','.',version mod 10 + '0'
	db	0
	call	crlf
;
;	check if file was specified
;
	lxi	h,deffcb+1
	mvi	a,' '
	cmp	m
	jz	leaveflags
;
;	process file in defalut fcb at 5ch
;
again:
	lxi	d,deffcb	;use default fcb
	mvi	c,searchf	;find file
	call	bdos
	cpi	0ffh		;ff if not found
	jz	nofile
	lxi	h,dmarea	;
	rlc			;calculate address of found fcb
	rlc
	rlc
	rlc
	rlc
	mov	e,a
	mvi	d,0
	dad	d
	shld	filefcb		;save absolute fcb address
	if	homeimp	;if using home cursor screen must be erased
	call	erase	;initially
	endif
;
;	copy found fcb to a workspace
;
movoldtowk:
	lhld	filefcb
	lxi	d,workfcb
	lxi	b,filenamlen
	call	move
;
;	move drive code to workfcb
;
	lda	deffcb		;get drive code
	sta	workfcb		;put drive code into workfcb
;
;	main loop - this changes/displays flags in workfcb
;
doover:	call	doheader	;print top of page
	call	displayflags	;show flags status
	call	crlf
	call	crlf
	call	inlnprt
	db	'         Enter letter of flag to change or option > '
;
;	need to erase old char if not erasing screen each time
;
	if	homeimp
	db	' ',bs,0
	else
	db	0
	endif
;
;	get character from operator
;
	mvi	c,conin
	call	bdos
	cpi	esc
	jz	movoldtowk	;get old flags
	cpi	3
	jz	leaveflags	;quit
	cpi	ctlu
	jz	updfile		;change flags in directory
	ori	20h	;make lower case
	cpi	'l'
	jnc	doover		;out of range, loop back
	cpi	'a'
	JC	DOOVER		;out of range, loop back
;
;	Change flag in temporary fcb
;	a has flag position in 4 ls bits
;
	lxi	h,workfcb	;point to name
	ani	0fh		;kill ascii
	mov	e,a		;put into de
	mvi	d,0
	dad	d		;point to absolute address 
	mov	a,m		;get byte
	xri	80h		;toggle flag
	mov	m,a		;put it back
	jmp	doover		;loopbac to begining
;
;	update flags in directory
;
updfile:
	lxi	d,workfcb
	lda	deffcb		;get drive code
	stax	d		;set drive code in filename for setattr
	mvi	c,setattr
	call	bdos
	jmp	leaveflags
;
;	print top of page
;
doheader:
	if	homeimp
	call	homecur
	else
	call	erase
	endif
	call	inlnprt
	db	0DH,0AH,0AH
	db	'  File Parameter Flag Display/Change'
	db	' ver '
	db	version/10 + '0','.',version mod 10 + '0'
	db	0DH,0AH,0AH
	db	'          Options:            ^C - leave as is'
	db	0DH,0AH
	db	'                              ^U - update file'
	db	0Dh,0AH
	db	'                              ESC -original flags'
	db	0DH,0AH,0AH
	db	'	File: ',0 		
	lxi	h,workfcb
	call	shnm1		;show mane of file
	call	crlf
	call	crlf
	ret
;
;	move bc bytes from hl to de
;
move:	mov	a,b
	ora	c
	rz
	mov	a,m
	stax	d
	inx	h
	inx	d
	dcx	b
	jmp	move
;
;	display status of flags, menu style
;	workfcb contains file name with flags set
;
displayflags:
	mvi	a,'a'		;first letter of line
	sta	letterofline	;save for later
	lxi	h,flagsm	;point to start of flag descriptors
	shld	textpoint
	lxi	h,workfcb
	shld	flagpoint
displayloop:
	call	inlnprt
	db	'               ',0	;a crude tab
	lda	letterofline		;print line letter
	mov	e,a
	cpi	6ch		;must be less than 'l'
	rz
	inr	a
	sta	letterofline
	mov	a,e
	call	printchar
	mvi	a,' '
	call	printchar
;
;	point to next char in filename
;
	lhld	flagpoint
	inx	h
	shld	flagpoint
	mov	a,m
	ani	80h
	jz	displayblank
;
;	flag set - write SET
;
	call	displayset
	jmp	describflg
;
;	flag not set - write four blanks
;
displayblank:
	call	blanks4
;
;	now write flags discriptor text
;
describflg:
	lhld	textpoint
	xchg
	mvi	c,prstr
	call	bdos
	call	crlf
	lhld	textpoint
	lxi	d,ptextlength
	dad	d
	shld	textpoint
	jmp	displayloop
;
;	send char in a to con:
;
printchar:
	mov	e,a
	push	h
	push	b
	mvi	c,conout
	call	bdos
	pop	b
	pop	h
	ret
;
;	write four blanks
;
blanks4:
	call	inlnprt
	db	'    ',0
	ret
;
;	display the work SET
;
displayset:
	call	inlnprt
	db	'SET ',0
	ret
;
;	search didn't find file
;	
nofile:
	call	erase
	call	inlnprt
	db	0ah,0ah,0ah,0ah,9,9
	db	0
	lxi	h,deffcb
	call	shnm1
	call	inlnprt
	db	' was not found.',0
	jmp	leaveflags1
crlf:
	call	inlnprt
	db	0DH,0AH,0
	ret
;
;	display a file name
;	hl points to file name/type as in fcb
;
showname:
	lhld	filefcb
shnm1:			;calling program set pointer
	push	h
;
;	first show drive code if not current
;
	mov	a,m
	inx	h	;point to first char of name
	ora	a	;set flags
;
;	print drive code if not current
;
	jz	dispfn
	adi	'@'
	call	printchar
	mvi	a,':'
	call	printchar
;
;	print filename
;	
dispfn:	mvi	c,8	;max length of filename
	call	dispfnft
;
;	then a dot
;
	mvi	a,'.'
	call	printchar
;
;	and last the filetype
;
	pop	h	;get begining of name
	lxi	b,9	;namelength + drive code length
	dad	b	;point to filetype
	mvi	c,3	;max length of filetype
	call	dispfnft
	ret
;
;	display print character until count in c up or ' ' found
;
dispfnft:
	mov	a,m		;get char from fcb
	cpi	' '		;quit if space
	rz
	call	printchar	;print character
	inx	h		;next charw
	dcr	c
	rz			;quit if count up
	jmp	dispfnft
;
;	In line print
;
inlnprt:
	pop	h	;get address of string
inlnloop:
	mov	a,m
	ora	a
	jz	inlndone
	mov	e,a
	mvi	c,conout
	push	h
	call	bdos
	pop	h
	inx	h
	jmp	inlnloop
inlndone:
	inx	h	;push to code after text
	pchl		;go there
;
;	exit this program
;	give user a few choices
;
leaveflags:
leaveflags1:
	call	inlnprt
	db	0dh,0ah,0ah,0ah,09h
	db	'Enter file or RETURN to exit > ',0
	lxi	h,combuff
;
;	fill buffer with ' ' so makefcb sees proper terminator
;
	push	h
	pop	d
	lxi	b,combuflen
	mvi	a,' '
	call	fillb		;in makefcb.lib
;	
	mvi	m,combuflen-1	;set max
	xchg
	mvi	c,readbuff
	push	d
	call	bdos
	pop	d
	xchg
	inx	h
	mov	a,m
	ora	a
	jnz	newfile	;if zero length then quit 
	lhld	oldstack
	sphl
	ret		;to ccp with old stack intact
newfile:
	inx	h		;point to start of command string
	lxi	d,deffcb 	;where to build fcb
	call	makefcb		;make fcb from string
	jnc	again		;if no error do flags again
	call	crlf
	call	inlnprt
	db	9,9
	db	'Bad file name: ',0
	lxi	h,deffcb
	call	shnm1
	jmp	leaveflags1
;
;	erase screen
;
erase:
	if 	lineeded
	mvi	a,lichar
	call	printchar
	endif
	mvi	a,clrchar
	jmp	printchar
;
;	home cursor	(optional)
;
	if	homeimp
homecur:
	endif
	if	homeimp and lineeded
	mvi	a,lichar
	call	printchar
	endif
	if	homeimp
	mvi	a,homechar
	jmp	printchar
	endif
;
;
;	flag descriptors
;	these must remain 16 chars long or change ptextlength
;
flagsm:	
	DB	'f1 no xmdm CP/M$'
	DB	'f2 no xmdm MP/M$'
	DB	'f3             $'
	DB	'f4             $'
; above for user -- below reserved for system
	DB	'f5             $'
	DB	'f6             $'
	DB	'f7             $'
	DB	'f8             $'
        db	'read only      $'
	DB	'no directory   $'
	DB	't3             $'

;
;	make fcb from string with unambiguous file name
;	hl=filename; de=fcb
;	returns with carry set if bad name
;
makefcb:
	xra	a
	sta	flag	;flag non-zero if invalid char in name
	push	h	;save command pointer
	push	d	;save fcb pointer
;
;	clear fcb
;
	lxi	b,36
	call	clrb
;
;	put blanks in filename
;
	pop	d
	push	d
	inx	d	;point to start of filename
	lxi	b,11	;length of name + type
	mvi	a,' '	;char to fill
	call	fillb
;
;	skip any leading blanks in filename string
;
	call	skipb
;
;	look if drive specified
;
	pop	d	;get fcb
	xchg
	shld	mfcbfcb
	xchg
	pop	h	;get filename

	call	checkdrive
	inx	d	;point to file name in fcb
;
;	process filename
;	eight chars or until '.'
;
	mvi	c,8
	call	getname
;
;	there may be a dot here if we counted down to zero
;
	mov	a,m
	cpi	'.'
	jnz	nodot
	inx	h	;skip dot
nodot:
;
;	adjust de to start of filetype in fcb
;
	push	h
	lhld	mfcbfcb	;get fcbstart
	lxi	d,9	;offset from start of fcb to filetype
	dad	d
	xchg		;de is at filetype of fcb
	pop	h	;hl is at filetype (or 9th char of filename)
;
;	process filetype
;
	mvi	c,3
	call	getname
	lda	flag
	adi	1	;set carry if bad name
	ret
;
;	move chars from (hl) to (de) until count in c is up or '.' found
;
getname:
	mov	a,m
	inx	h
	call	upcase	;make upper case if lower
	call	checkvalid	;set flag if invalid
	cpi	'.'	;look for seperator
	rz
	cpi	' '
	rz
	stax	d	;put into fcb
	inx	d
	dcr	c	;count down
	rz	
	jmp	getname
;
;	check if char is legal
;	make flag non-zero if fails
;
checkvalid:
	cpi	'*'
	jz	badchar
	cpi	'['
	jz	badchar
	cpi	']'
	jz	badchar
	cpi	','
	mov	b,a
	ani	30h
	cpi	30h
	mov	a,b
	rnz		;char is valid in filename
	cpi	':'
	rc		;3xH chars less than : are ok
badchar:
	mvi	a,0ffh
	sta	flag
	ret
;
;	check and process drive
;	hl at start at first char of filename
;	put drive code into fcb pointed to by de, if there
;
checkdrive:
	inx	h	;2nd byte is a colon if drive spec'd
	mov	a,m
	dcx	h	;point back to beginingv
	cpi	':'
	rnz		;no ':' no drive
	mov	a,m
	call	upcase	;make upper
	ani	0fh	;remove ascii bias
	stax	d	;put into drive code of fcb
	inx	h	;point to colon
	inx	h	;point to first char of name
	ret
;
;	skip blanks in filename
;	hl left pointing at first non-blank
;
skipb:	mov	a,m
	cpi	' '
	rnz
	inx	h
	jmp	skipb
;
;	convert character to upper case (if needed)
;	char in and returned in a
;
upcase:	cpi	'`'	;' has 60h bits set but is not lower case
	rz
	cpi	'{'	;{ and above are good too
	rnc
	push	psw	;save char
	ani	60h	;isolate bits
	cpi	60h
	jnz	notlower
	pop	psw
	ani	5fh	;make upper
	ret
notlower:
	pop	psw
	ret
;
;	fill bc bytes with char in a, starting at de
;
clrb:	mvi	a,0
fillb:	inr	b
	dcr	b
	jnz	fillb1
	inr	c
	dcr	c
	rz
fillb1:	stax	d
	inx	d
	dcx	b
	jmp	fillb
;
;	ram storage area
;
workfcb:		;this is the temporary filename
	ds	36	;used for all operations
letterofline:		;letter for display
	ds	1
combuff:		;readbuffer for bdos cmd 10
	ds	combuflen
flagpoint:		;points to character in workfcb 
	ds	2
textpoint:		;points to flag descriptor in flagsm
	ds	2
oldstack ds	2	;save stack pointer for no-boot return
filefcb	ds	2	;absolute address of fcb
mfcbfcb	ds	2	;address of fcb under constructio for makefcb
flag:	ds	1	;ff if bad char in filename
	ds	30
stacktop equ	$	;private stack
	end
