; SYM1_ASM on D61
; 19th March 1998
;
; To produce an EQU table from a _SYM file
;
WHITE	EQU	7
BLACK	EQU	0
GREEN	EQU	4
RED	EQU	2
VAL	EQU	26
TYPE	EQU	6
BUF_SIZE	EQU	60
SL	EQU	0
NL	EQU	6
SEC_LEN	EQU	$C
LAB_LEN	EQU	$24
LINF_LEN	EQU	$30
SEC_NO	EQU	$3C
DAT_ST	EQU	$3E
CHLEN	EQU	512
LLEN	EQU	520
	RS_SET	0
PROMPT	RS.B	42
BUF	RS.L	64
O_BUF	RS.L	64
CH_ID	RS.L	1
AL_SP	RS.L	1
LBUF	RS.L	64
ID_CON	RS.L	1
SEC_REC	RS.L	8
SEC_NW	RS.L	1
SINF_W	RS.L	1
LAB_NW	RS.L	1
LINF_W	RS.L	1
STR_CT	RS.W	4
N_OFF	RS.W	3
LAB_ST	RS.W	3
TK2_BUFFER	RS.B	52
;
FILE	EQU	PROMPT+2
VERSION	EQU	?"2.7"
TAB	EQU	9
TAB_SP	EQU	9*256+32
;
	BRA.S	START
	DS.L	1
	DC.W	$4AFB
NAM	DC.W	NAME-NAM-2
	DC.B	"TRA_SYM V",VERSION," MAR 98"
NAME	DS.B	0
;
START	LEA	(A6,A5.L),A7        STACK
	LEA	(A6,A4.L),A6        -> DATA SPACE
	LEA	CON,A1
	MOVE.W	UT_CON,A2
	JSR	(A2)
	MOVE.L	A0,ID_CON(A6)
	PEA	FILEDEV
	PEA	PROMPT(A6)
	BSR	QSTRCPY
GWAG1	MOVEQ	#7,D0
	LEA	SEC_REC(A6),A0
GWAG3	CLR.L	(A0)+
	DBF	D0,GWAG3
	MOVEA.L	ID_CON(A6),A0
	MOVEQ	#-1,D3
	MOVEQ	#SD_CLEAR,D0
	TRAP	#3        clears window
	MOVE.B	CON,D1    color -> D1
	MOVE.B	CON+1,D2
	EXT.W	D2        width -> D2
	MOVEQ	#SD_BORDR,D0
	TRAP	#3
	LEA	HEAD0,A1
	BSR	UMT1
	LEA	HEAD0A,A1
	BSR	UMT1
	LEA	HEAD0B,A1
	BSR	UMT1
	BSR	CURON     put on cursor
;
;         Menu
;
GWAG2	MOVEQ	#IO_FBYTE,D0
	TRAP	#3
	CMPI.B	#244,D1
	BEQ.S	GWAG1     F4 - redraw
	ADDQ.B	#1,D1
	CMPI.B	#'2',D1
	BEQ.S	REPRINT
	CMPI.B	#'3',D1
	BNE.S	GWAG2     get 1,2, or F4
REPRINT	MOVE.B	D1,D2
	SUB.B	#48,D2
	MOVE.B	D2,D7     keep 1,2 in D7
	MOVEQ	#WHITE,D1
	BSR	INK
	MOVEQ	#0,D1
	BSR	AT
	CMPI.B	#2,D2
	BEQ.S	REP1      process
	LEA	HEAD0B,A1
	BRA.S	REP2      quit
REP1	LEA	HEAD0A,A1
REP2	BSR	UMT1
	MOVEQ	#GREEN,D1
	BSR	INK
	BSR	CUROF
	CMPI.B	#2,D7
	BNE	QUIT1     EXIT for good!
REP3	MOVEQ	#0,D1    re-entry after BEEP
	MOVEQ	#5,D2
	BSR	AT
	LEA	HEAD1,A1
	BSR	UMT1
	MOVEQ	#SD_NL,D0
	TRAP	#3        new line
	LEA	BUF(A6),A1    to get X-POS etc
	MOVEQ	#SD_CHENQ,D0
	TRAP	#3
	MOVE.W	BUF+4(A6),D1  X-POS
	SWAP	D1
	MOVE.W	prompt(A6),D1
	MOVE.W	#40,D2    buffer length
	LEA	prompt+2(A6),A1
	ADDA.W	D1,A1
	MOVEQ	#IO_EDLIN,D0
	TRAP	#3
	LEA	prompt(A6),A0
	MOVE.L	A1,D0
	LEA	prompt+2(A6),A1
	SUB.L	A1,D0
	SUBQ.W	#1,D0
	MOVE.W	D0,(A0)   set length of name
	BEQ	GWAG1     No file - try again
	MOVEQ	#0,D3     OPEN_IN
	BSR	OPENFILE
	BNE	BEEP      can't open - try again
	MOVE.L	A0,CH_ID(A6)   keep ID
	MOVEQ	#64,D2    header length
	MOVEQ	#-1,D3
	LEA	O_BUF(A6),A1  space for header
	MOVEQ	#FS_HEADR,D0
	TRAP	#3
	TST.L	D0
	BNE	BEEP1      can't open!!
	TST.B	-59(A1)   check type
	BNE	BEEP1      not type 0
;
	MOVE.L	-64(A1),D1          length of file
	CMPI.L	#$3E,D1
	BLT	BEEP1
	MOVE.L	D1,D4
	ADDQ.L	#2,D1     safety factor
	MOVEQ	#-1,D2    this job
	MOVEQ	#MT_ALCHP,D0
	TRAP	#1
	TST.L	D0
	BNE	ER_OM    ---->
	MOVE.L	A0,AL_SP(A6)
	MOVEA.L	A0,A5
	MOVE.L	D4,D2     length of file
	MOVEQ	#-1,D3
	MOVEA.L	A0,A1
	MOVEA.L	CH_ID(A6),A0
	MOVEQ	#FS_LOAD,D0
	TRAP	#3
	TST.L	D0
	BNE	ER_NF ---->   can't load
;
; A5 = LAB LIST
; A0 is the file ID
;
	MOVEQ	#IO_CLOSE,D0
	TRAP	#2        close file
;
	LEA	PROMPT(A6),A1
	MOVE.W	(A1),D2
	ADDQ.W	#4,(A1)
	LEA	2(A1,D2.W),A1
	MOVEQ	#3,D2
	LEA	TRAIL1,A2
PRO1	MOVE.B	(A2)+,(A1)+
	DBF	D2,PRO1
	LEA	PROMPT(A6),A0
	MOVEQ	#3,D3
	BSR	OPENFILE
	TST.L	D0
	BNE	ER_NOPE ---->
	MOVE.L	A0,CH_ID(A6)
;
; INNER LOOP
;
	LEA	([AL_SP,A6],DAT_ST),A0
	LEA	([AL_SP,A6],SEC_LEN),A2
	LEA	SEC_NW(A6),A1
	LEA	STR_CT(A6),A3
	MOVEQ	#3,D0
SET_1	MOVE.L	A0,(A1)+
	MOVEQ	#0,D1     count of strands
	MOVEQ	#2,D3     count strands
	CMPI.W	#1,D0
	BGT	SET_2
	BEQ	SET_4     lab names
	MOVEA.L	AL_SP(A6),A5        address of labels
	LEA	LAB_ST(A6),A4
	BRA	SET_2
SET_4	LEA	([AL_SP,A6],NL),A5  address of name positions
	LEA	N_OFF(A6),A4
SET_2	MOVE.W	(A5)+,D7  no effect if D0 = 2 or 3
	MOVE.L	(A2)+,D2
	BEQ.S	SET_3     no strand here
	ADDQ.W	#1,D1
	ADDA.L	D2,A0     advance address
	CMPI.W	#1,D0
	BGT	SET_3
	MOVE.W	D7,(A4)+
SET_3	DBF	D3,SET_2
	MOVE.W	D1,(A3)+  set number of strands
	DBF	D0,SET_1
;
	MOVE.W	([AL_SP,A6],SEC_NO),D3
	BEQ	LOOP8     no sections
	CMPI.W	#256,D3
	BGT	ER_TYPE   ----> not a _SYM file
	MOVEQ	#-1,D3
	MOVEA.L	CH_ID(A6),A0
	MOVE.W	STR_CT(A6),D7       count strands
	MOVEA.L	SEC_NW(A6),A2
	MOVEA.L	SINF_W(A6),A3
	MOVE.L	A3,D5
	BRA	LOOP9
;
LOOP1	LEA	CHLEN(A2),A4        -> next CHUNK
	MOVEA.L	A2,A5
	ADDA.L	(A2)+,A5  -> end of names
	MOVE.L	(A2)+,D6  0 if end of strand
	BRA	LOOP3
LOOP2	BSR	SPB       fill O_BUF with spaces
LOOP10	LEA	8(A3),A3  to next info item
	CMPA.L	D5,A3
	BLT	LOOP11    OK
	MOVEA.L	D5,A3     next chunk
	ADDI.L	#LLEN,D5
	BRA	LOOP10
;
LOOP11	BSR	DO_SC     set "SECTION" or "COMMON"
LOOP3	CMPA.L	A5,A2     end of CHUNK? ...
	BLT.S	LOOP2     .... no
	MOVEA.L	A4,A2     step to next CHUNK
	TST.L	D6        end of strand? ....
	BNE	LOOP1     .... no
LOOP9	DBF	D7,LOOP1  count strands
;
	MOVEQ	#0,D7     set markers for XREF etc
	BSR	DOL
	MOVE.L	#$FE0000,D7
	BSR	DOL       do Type 5
	MOVE.L	#$FD0000,D7
	MOVEA.L	SEC_NW(A6),A2
	MOVEA.L	SINF_W(A6),A3
	BSR	DOL_R     do SECTIONs and Type 6
	BRA	END
;
LOOP8	MOVE.L	#$FE0002,D7
	BSR	DOL       do Type 5
	MOVE.L	#$FFFF0002,D7
	BSR	DOL       do Type 6 (all)
;
END	MOVEA.L	CH_ID(A6),A0
	MOVEQ	#IO_CLOSE,D0
	TRAP	#2
END2	MOVEA.L	AL_SP(A6),A0
	MOVEQ	#MT_RECHP,D0
	TRAP	#1
	LEA	PROMPT(A6),A0
	SUBQ.W	#4,(A0)   strip off _SYM from prompt
	BPL.S	END1
	ADDQ.W	#4,(A0)   add back if <0
END1	BRA	GWAG1
;
DOL	MOVEA.L	LAB_NW(A6),A2
	MOVEA.L	LINF_W(A6),A3
	MOVEQ	#0,D4     mark 'names'
	MOVE.W	STR_CT+4(A6),D7
	BRA	DOL_R8
DOL_R	MOVEQ	#-1,D4    mark 'sections'
	MOVE.W	STR_CT(A6),D7
DOL_R8	MOVE.W	D7,D4
	MOVE.L	A3,D5
	BRA	DOL_R9
;
DOL_R6	MOVEA.L	D5,A3
	ADDI.L	#LLEN,D5  to end of inf CHUNK
	MOVE.W	D4,D0
	SUB.W	D7,D0
	LEA	CHLEN(A2),A4        -> next CHUNK
	MOVEA.L	A2,A5
	ADDA.L	(A2),A5   to end of names
	MOVE.L	4(A2),D6
	TST.L	D4        +=names -=sections
	BMI	DOL_R7
	ADDA.W	N_OFF-2(A6,D0.W*2),A2          -> 1st name
	BFEXTU	LAB_ST-2(A6,D0.W*2){8:6},D0    offset to info
	LSL.L	#3,D0     -> info - 8
	ADDA.L	D0,A3
	BRA	DOL_R2
DOL_R7	LEA	8(A2),A2  -> 1st section name
	BRA	DOL_R2
DOL_R1	LEA	CHLEN(A2),A4        to next name CHUNK
	MOVEA.L	A2,A5
	ADDA.L	(A2)+,A5  end of names in CHUNK
	MOVE.L	(A2)+,D6  0 = end of strand
DOL_R2	LEA	8(A3),A3  step to next inf item
	CMPA.L	D5,A3     end of CHUNK? ....
	BLT	DOL_R3    .... no
	MOVEA.L	D5,A3     -> next CHUNK
	ADDI.L	#LLEN,D5  and next one
	BRA	DOL_R2
DOL_R3	BFEXTU	D7{14:2},D0  0=XREF etc 1=SECT 2=T5 3=T6
	BNE	DOL_R4    not XREF etc
	MOVE.W	(A3),D1   section no
	MOVE.W	D1,D0
	LSR.W	#3,D0
	NEG.W	D0
	CMPI.B	#6,TYPE+1(A3)
	BNE.S	DOL_R10
	BSET	D1,SEC_REC(A6,D0.W) set section's bit if type 6
DOL_R10	BFEXTU	6(A3){2:2},D1       0=normal 1=XDEF 2=XREF 3=pseudo XREF
	BEQ	XR3	normal
	CMPI.B	#3,D1	pseudo XREF? . .
	BNE.S	XR1	. . no - XDEF or XREF
XR3	MOVE.B	(A2)+,D0
	EXT.W	D0
	LEA	(A2,D0.W),A2        step to next name
	BRA	DOL_R5
XR1	BSR	SPB       fill O_BUF with spaces
	TST.B	UNSP
	BEQ       XR5
	MOVE.W	#TAB_SP,(A1)+
	BRA	XR6
;
XR5	LEA	9+O_BUF(A6),A1
XR6	MOVE.L	#'XREF',(A1)+
	SUBQ.L	#1,D1     0=XDEF
	BEQ	XR4
	BTST	#0,1+TYPE(A3)       PC? . .
	BEQ	XR2                 . . yes
	BFEXTU	TYPE(A3){0:2},D0
	MOVE.W	XSZE(D0.W*2),(A1)+	set size
	BRA	XR2
XR4	MOVE.B	#'D',-3(A1)
XR2	MOVE.B	#TAB,(A1)+
	BSR	DO_LIN    output line
DOL_R5	CMPA.L	A5,A2     end of CHUNK? ....
	BLT	DOL_R2    .... no
	MOVEA.L	A4,A2     -> next CHUNK
	TST.L	D6        end of strand? ....
	BNE	DOL_R1    .... no
DOL_R9	DBF	D7,DOL_R6 count strands
	RTS
;
XSZE	DC.W	'.B','.W','.L','??'
;
DOL_R4	CMPI.L	#1,D0
	BEQ	D_SEC     SECTION
	MOVE.L	D7,D1
	SWAP	D1
	ADDQ.B	#7,D1     '5' or '6'
	BFEXTU	TYPE(A3){10:6},D3
	CMP.B	D3,D1     is label right type? ....
	BNE	XR3       .... no
	BFEXTU	TYPE(A3){6:2},D3    0=EQU, 1=RGL, 2=REG
	BTST	#6,1+TYPE(A3)
	BEQ	DOL_R11   EQU not SET
	MOVEQ	#3,D3     mark SET
DOL_R11	CMPI.B	#5,D1
	BEQ	T56_1
	BFEXTU	D7{0:8},D0
	BMI	T56_1     no sections
	CMP.B	1(A3),D0
	BNE	XR3       not right section
T56_1	BSR	SPB       spaces to O_BUF
	BSR	N_INA     put name in to start of buffer
	TST.B	UNSP
	BEQ	T56_5
	MOVE.B	#TAB,(A1)+
	BRA	T56_6
;
T56_5	LEA	33+O_BUF(A6),A1
T56_6	MOVE.L	CMD(D3.W*4),(A1)+   EQU, SET, EQUR or REG
	TST.W	D3
	BEQ	DOL_R12   EQU
	CMPI.B	#3,D3
	BNE	RGX       neither EQU nor SET
DOL_R12	BTST	#16,D7    0='5' 1='6'
	BEQ	T56_2
	MOVE.L	#' *+$',(A1)+
	BRA.S	T56_3
T56_2	MOVE.W	#' $',(A1)+
T56_3	MOVEM.L	A2-3/A6,-(A7)
	LEA	2(A3),A6  value of label
	MOVEA.L	A1,A0
	SUBA.L	A1,A1
	SUBA.L	A6,A0
	MOVEA.W	CN_ITOHL,A2
	JSR	(A2)
	ADDA.L	A6,A0
	MOVEM.L	(A7)+,A2-3/A6
T56_4	MOVE.B	#10,(A0)+ LF
	MOVE.L	A0,D2
	LEA	O_BUF(A6),A1
	SUB.L	A1,D2
	MOVEA.L	CH_ID(A6),A0
	MOVEQ	#-1,D3
	MOVEQ	#IO_SSTRG,D0
	TRAP	#3
	TST.L	D0
	BNE	ER_OM     ---->
	BRA	DOL_R5
;
; D3=1 RGL - 2 REG
;
RGX	MOVE.B	#' ',(A1)+
	MOVE.L	2(A3),D2  value
	CMPI.W	#1,D3
	BEQ	RGXL      RGL
	BCLR	#3,D2
	BNE	RGX2      'A'
	MOVE.B	#'D',(A1)+
	BRA	RGX3
RGX2	MOVE.B	#'A',(A1)+
RGX3	ADDI.B	#'0',D2
	MOVE.B	D2,(A1)+
	MOVEA.L	A1,A0
	BRA	T56_4
;
RGXL	MOVEQ	#'D'*2-'A',D0
RGXL1	MOVEQ	#'0',D1
	ADDI.B	#'A'-'D',D0         set 'D' then 'A'
	MOVEQ	#7,D3
RGXL2	LSR.L	#1,D2               look at next register
	BCC	RGXL3               no reg
	MOVE.B	D0,(A1)+
	MOVE.B	D1,(A1)+
	MOVE.B	#'/',(A1)+
RGXL3	ADDQ.B	#1,D1
	DBF	D3,RGXL2
	CMPI.B	#'A',D0             ended? . .
	BNE	RGXL1               . . no
	LEA	-1(A1),A0           cut off last '/' (or SPACE)
	BRA	T56_4
;
D_SEC	MOVE.W	(A3),D1   SECTION
	MOVE.W	D1,D0
	LSR.W	#3,D0
	NEG.W	D0
	BTST	D1,SEC_REC(A6,D0.W)
	BEQ	XR3       not this section
	BSR	SPB       spaces to O_BUF
	BSR	DO_SC
	MOVEM.L	D4-7/A1-5,-(A7)
	MOVE.W	(A3),D7
	LSL.W	#8,D7
	MOVE.B	#-1,D7    mark '6'
	SWAP	D7
	BSR	DOL       do type 6 for this section
	MOVEM.L	(A7)+,D4-7/A1-5
	BRA	DOL_R5
;
SPB	TST.B	UNSP
	BEQ	SPB_2	spaces
	LEA	O_BUF(A6),A1
	BRA	SPB_3
;
SPB_2	MOVEQ	#12,D0
SPB_1	MOVE.L	#$20202020,O_BUF(A6,D0.W*4)
	DBF	D0,SPB_1
SPB_3	RTS
;
DO_SC	TST.B	UNSP
	BEQ	DO_SC2
	MOVE.B	#TAB,(A1)+
	BRA	DO_SC3
;
DO_SC2	LEA	8+O_BUF(A6),A1
DO_SC3	TST.W	TYPE(A3)  test if SECTION or COMMON
	BEQ	DO_SC1    SECTION
	MOVE.L	#"COMM",(A1)+
	MOVE.L	#"ON  ",(A1)+
	BRA	DO_LIN
DO_SC1	MOVE.L	#'SECT',(A1)+
	MOVE.L	#'ION ',(A1)+
DO_LIN	BSR	N_IN	put in name
	MOVE.B	#10,(A1)+  LF
	MOVE.L	A1,D2
	LEA	O_BUF(A6),A1
	SUB.L	A1,D2	length
	MOVEQ	#IO_SSTRG,D0
	TRAP	#3
	TST.L	D0
	BNE	ER_OM     ---->
	RTS
;
N_INA	LEA	O_BUF(A6),A1        name to start
N_IN	MOVE.B	(A2)+,D0  length
	EXT.W	D0
;	MOVE.W	D0,D2
	BRA.S	N_IN1
N_IN2	MOVE.B	(A2)+,(A1)+
N_IN1	DBF	D0,N_IN2
	RTS
;
UMT	MOVEA.L	ID_CON(A6),A0
UMT1	MOVE.W	UT_MTEXT,A2
	JSR	(A2)
	RTS
;
CON	DC.B	230,2     border
	DC.B	RED,GREEN paper/ink
	DC.W	340,84,80,30
;
CMD	DC.L	'EQU ','REG ','EQUR','SET '
;
HEAD0	DC.W	HEAD0E-HEAD0-2
	DC.B	"             GDG SYM DECODER V",VERSION,10,10
HEAD0E	DS.B	0
HEAD0A	DC.W	20
	DC.B	"1  Decode _SYM file",10
HEAD0B	DC.W	8
	DC.B	"2  QUIT",10
HEAD1	DC.W	21
	DC.B	"Give source filename "
;
CURON1	MOVEQ	#-1,D3
CURON	MOVEQ	#SD_CURE,D0
	BRA.S	TP3
;
CUROF1	MOVEQ	#-1,D3
CUROF	MOVEQ	#SD_CURS,D0
	BRA.S	TP3
;
AT	MOVEQ	#SD_POS,D0
TP3	TRAP	#3
	RTS
;
INK	MOVEQ	#SD_SETIN,D0
	BRA.S	TP3
;
TRAIL1
	DC.B	'_LST'
;
BEEP1	MOVEQ	#IO_CLOSE,D0
	TRAP	#2
BEEP	BSR.S	BLP
	MOVEA.L	ID_CON,A0
	BRA	REP3
;
BLP	LEA	NOISE,A3
	MOVEQ	#MT_IPCOM,D0
	TRAP	#1
	RTS
;
NOISE	DC.B	10,8
	DC.L	$AAAA
	DC.B	1,20,90,0,$10,$27
	DC.B	$F4,$A2,1,0
;
QUIT1	MOVEQ	#MT_FRJOB,D0
	MOVEQ	#-1,D1
	TRAP	#1
;
ER_OM	LEA	OM,A2
	BRA.S	OUT
;
ER_NF	LEA	NF,A2
	BRA.S	OUT
;
ER_NOPE	LEA	NOPE,A2
OUT	MOVEQ	#3,D1
	MOVEQ	#8,D2
	BSR.S	AT
	MOVEA.L	A2,A1
	BSR	UMT
	BSR	PAUSE
	BRA	QUIT1
;
ER_TYPE	MOVEA.L	CH_ID(A6),A0
	MOVEQ	#IO_CLOSE,D0
	TRAP	#2
;          MOVEQ     #-1,D1
	LEA	PROMPT(A6),A0
;          TRAP      #2
	BSR	DELETEFILE
	BSR	BLP
	MOVEA.L	ID_CON(A6),A0
	MOVEQ	#3,D1
	MOVEQ	#8,D2
	MOVEQ	#-1,D3
	BSR.S	AT
	MOVEQ	#BLACK,D1
	BSR	INK
	LEA	SOPE,A1
	BSR	UMT1
	MOVEQ	#GREEN,D1
	BSR	INK
	SUBA.L	A1,A1
	MOVEQ	#MT_SUSJB,D0
	MOVEQ	#-1,D1
	MOVEQ	#100,D3
	TRAP	#1
	BRA	END2
;
PAUSE	MOVEQ	#-1,D1    this job
	SUBA.L	A1,A1
	MOVEQ	#MT_SUSJB,D0
	MOVE.W	#150,D3   timeout
	TRAP	#1
	RTS
;
;======================================================================
;                       STRING HANDLING
;
;   Useful string handling routines.
;
;   - These are based on C68 C style routines adapted to handle QL strings.
;   - Parameters are passed on the stack.
;   - All registers are preserved.
;   - The calling routines must tidy the stack.
;----------------------------------------------------------------------
;   Copy a QL string
;       4(A7) = Target
;       8(A7) = Source

QSTRCPY
	MOVEM.L	D0/A0-A1,-(A7)              ; save regosters used
	MOVE.L	12+4(A7),A1                 ; Target address
	MOVE.L	12+8(A7),A0                 ; Source address
	MOVE.W	(A0),D0                     ; Length to copy
	MOVE.W	(A0)+,(A1)+                 ; Copy length field
	BRA	QSTRCPY2            ; Remove if NULL byte at end wanted
QSTRCPY1	MOVE.B	(A0)+,(A1)+                 ; Copy a byte
QSTRCPY2	DBRA	D0,QSTRCPY1                 ; loop until finished
	MOVEM.L	(A7)+,D0/A0-A1              ; restore saved registers
	RTS

;   Concatenate a QL string onto another one
;       4(A7) = Target
;       8(A7) = Source

QSTRCAT
	MOVEM.L	D0/A0-A1,-(A7)
	MOVE.L	12+4(A7),A1                 ; Target address
	MOVE.L	12+8(A7),A0                 ; Source address
	MOVE.W	(A1),D0                     ; get old length
	ADD.W	(A0),D0                     ; Calculate new length
	MOVE.W	D0,(A1)+                    ; Store new length
	SUB.W	(A0),D0                     ; Reset to old length
	ADDA.W	D0,A1                       ; skip over current data
	MOVE.W	(A0)+,D0                    ; get length to copy
	BRA	QSTRCPY2


;   Copy a QL string with maximum length check
;       4(A7).L  = Target
;       8(A7).L  = Source
;       12(A7).W = Maximum length

QSTRNCPY
	MOVEM.L	D0-D1/A0-A2,-(A7)
	MOVE.L	20+4(A7),A1             ; Target address
	MOVE.L	A1,A2                   ; ... copied to A2
	MOVE.L	20+8(A7),A0             ; Source address
	MOVE.W	20+12(A7),D1            ; Maximum length
	MOVE.W	(A0)+,D0                ; Length to copy
	CLR.W	(A1)+                   ; Clear target length
	BRA	QSTRNCPY2
QSTRNCPY1	CMP.W	(A2),D1                 ; Check max length  not reached
	BEQ	QSTRNCPY3               ; If so exit immediately
	ADDQ.W	#1,(A2)                 ; Update length
	MOVE.B	(A0)+,(A1)+             ; ... and copy byte
QSTRNCPY2	DBRA	D0,QSTRNCPY1            ; Loop until finished
QSTRNCPY3	MOVEM.L	(A7)+,D0-D1/A0-A2
	RTS

;   Concatenate a QL string onto another one with maximum length check
;       4(A7) = Target
;       8(A7) = Source

QSTRNCAT
	MOVEM.L	D0-D1/A0-A2,-(A7)
	MOVE.L	20+4(A7),A1             ; Target address
	MOVE.L	A1,A2                   ; copied to A2
	MOVE.L	20+8(A7),A0             ; Source address
	MOVE.W	20+12(A7),D1            ; Maximum length
	MOVE.W	(A1)+,D0                ; Existing length
	ADDA.W	D0,A1                   ; Skip over source length
	MOVE.W	(A0)+,D0                ; Length to copy
	BRA	QSTRNCPY2               ; Join QSTRNCPY code

;======================================================================
;                          FILE HANDLING
;
;   Friendly versions of file open/delete that will
;   allow use of TK2 directories in names.
;
;   These routines assume that the parameters have been set up
;   for the respective TRAP #2 call.  They can then be called
;   in place of the TRAP #2 routine.
;-----------------------------------------------------------------------

;   When we OPEN a file we want to try the open in
;   the following sequence of events:
;     - The name exactly as supplied
;     - If that fails, the name with the DATA_USE directory
;       added to the front.

OPENFILE
	MOVEQ	#IO_OPEN,D0
	MOVEQ	#-1,D1
	MOVEM.L	D0/A0,-(A7)                    ; Save name pointer

;       We start by trying the name exactly as passed

	TRAP	#2                          ; Try operation
	TST.L	D0                          ; OK?
	BEQ	OPENEXIT                    ; YES, jump

;       If we failed with the first try, we now want
;       to try with the DATA_USE directory added

	MOVEM.L	0(A7),D0/A0                 ; restore saved registers
	BSR	DATA_USE
	TRAP	#2
	TST.L	D0

OPENEXIT	ADDA.W	#2*4,A7                     ; remove saved values
	TST.L	D0                          ; set condition code
	RTS

;   When we DELETE a file we want to try the delete in
;   the following sequence of events:
;     - The name exactly as supplied
;     - If that fails, the name with the DATA_USE directory
;       added to the front.

DELETEFILE
	MOVEQ	#IO_DELET,D0
	MOVEQ	#-1,D1
	MOVEM.L	D0/D1/A0,-(A7)              ; Save registers

;       We start by trying the name exactly as passed

	TRAP	#2                          ; Try operation
	TST.L	D0
	BEQ	DELEXIT

;       If we failed with the first try, we now want
;       to try with the DATA_USE directory added

	MOVEM.L	0(A7),D0/D1/A0              ; restore saved registers
	BSR	DATA_USE
	TRAP	#2

DELEXIT	ADDA.W	#3*4,A7                     ; remove saved values
	TST.L	D0                          ; set confition code
	RTS


; TK2_BUFFER  DS.B    50             ; Buffer to hold expanded filename
; TK2_BUFFERX DS.B    0  (Set in DATA SPACE)

;       Subroutine to get the current system
;       variables address.  This is returned
;       in A1 (which would have been corrupted
;       in both the OPEN and DELETE calls anyway)
;       with all other registers being preserved.

TK2_VALUES
	MOVEM.L	D0-D2/A0,-(A7)              ; save registers that get corrupted
	MOVEQ	#0,D0                       ; SMS.INFO
	TRAP	#1
	MOVE.L	A0,A1                       ; Move result to A1
	MOVEM.L	(A7)+,D0-D2/A0              ; Restore registers
	RTS

;       Get the DATA_USE value, and build up a name
;       which has this at the front followed by the
;       users name and try that.

DATA_USE
	BSR	TK2_VALUES
	MOVE.L	$B0(A1),A1                  ; Get DATA_USE pointer
DATA_USE1
	CMPA.L	#0,A1                       ; Is value NULL?
	BEQ	DATA_USE9                   ; ... YES, exit immediately

	MOVE.L	A1,-(A7)                    ; Source
	PEA	TK2_BUFFER(A6)              ; Target
	BSR	QSTRCPY
	ADDQ.L	#8,A7                       ; Remove parameters

	MOVE.W	#50,-(A7)                   ; Max length
	MOVE.L	A0,-(A7)                    ; Source
	PEA	TK2_BUFFER(A6)              ; Target
	BSR	QSTRNCAT
	ADDA.W	#10,A7                      ; Remove parameters
	LEA	TK2_BUFFER(A6),A0           ; set A0 to new filename
DATA_USE9	RTS

;       Get the PROG_USE value, and build up a name
;       which has this at the front followed by the
;       users name and try that.

PROG_USE
	BSR	TK2_VALUES
	MOVE.L	$AC(A1),A1
	BRA	DATA_USE1

;=========================================================================
;                           CONFIG BLOCK
;
;   This sets up a CONFIG block for options that the user might want
;   to pre-set.  The aim is to avoid having to have different
;   versions of this program for different defaults.
;-------------------------------------------------------------------------

; Config ID
	DC.L	'<<QC','FX>>'           ; Configuration ID
	DC.W	'01'                    ; Configuration level
CFGNAME	DC.W	CFGNAMEX-CFGNAME-2      ; Software name
	DC.B	'_SYM decoder'
CFGNAMEX	DS.B	0
CFGVER	DC.W	CFGVERX-CFGVER-2        ; Software Version
	DC.B	VERSION
CFGVERX	DS.B	0

item1	DS.W	0                       ; Word align

	DC.B	0
	DC.B	'D'
	DC.W	FILEDEV_MAX-*
	DC.W	0
	DC.W	0
	DC.W	DESCDEV-*
	DC.W	STRATT-*
;
ITEM2	DC.B	4,0
	DC.W	UNSP-*,0,0
	DC.W	DESUN-*
	DC.W	ATT_UN-*
term
	DC.W	-1                      ; Terminate list

;   description strings

DESCDEV	DC.W	DESCDEVX-DESCDEV-2
	DC.B	'Default source device'
DESCDEVX	DS.B	0
;
DESUN	DC.W	DESUNE-DESUN-2
	DC.B	'Choice of spaces or TABs'
DESUNE	DS.B	0

;   attributes

STRATT	DC.W	0                       ; No special attributes
;
ATT_UN	DC.B	0,0
ATT_SP	DC.W	ATT_SPE-ATT_SP-2
	DC.B	'Spaces'
ATT_SPE	DS.B	0
	DC.B	1,0
ATT_TB	DC.W	ATT_TBE-ATT_TB-2
	DC.B	'TABs'
ATT_TBE	DS.B	0
	DC.W	-1	

FILEDEV_MAX	DC.W	20
FILEDEV	DC.W	FILEDEVX-FILEDEV-2
	DC.B	'RAM1_'
FILEDEVX	DS.B	0
	DC.L	0,0,0,0
;
OM	DC.W	13
	DC.B	"Out of memory"
NF	DC.W	15
	DC.B	"Can't load file"
NOPE	DC.W	15
	DC.B	"Can't open file"
SOPE	DC.W	14
	DC.B	"Not a SYM file"

UNSP	DC.B	0