     DEFINT A-Z
     OPTION BASE 1
     DIM LN!(500),LN$(500),VBL$(500)

70   CLS
     PRINT TAB(12);"XREF 1.2  --  BASIC Programmer's Cross-reference Utility"
     PRINT TAB(22);"Copyright Thomas Hanlin III, 1985-1987"
     PRINT
     PRINT
     PRINT"Enter <V> to xref variables, <L> for line numbers, <X> to exit: ";
     GOOD$="VLX"
     GOSUB 1060
     PRINT A$
     IF A$="V" THEN 2000
     IF A$="X" THEN PRINT: PRINT: END

     CLEAR
1010 INPUT"File to xref";FIL$
     IF FIL$="" THEN 70
     IF FIL$="?" THEN FILES"*.BAS": GOTO 1010
     T=INSTR(FIL$,".")
     IF T THEN FIL$=LEFT$(FIL$,T) ELSE FIL$=FIL$+"."
     CALL EXIST(FIL$+"BAS"+CHR$(0),FILEXISTS)
     IF FILEXISTS=0 THEN PRINT"Missing file ";FIL$;"BAS": GOTO 1010
     OPEN"I",1,FIL$+"BAS"
     A$=INPUT$(1,1)
     CLOSE
     IF A$<>CHR$(255) THEN PRINT"Not a tokenized BASIC file.": GOTO 1010
     CALL UPCASE(FIL$)
     PRINT
     PRINT"Send results to <S>creen or <F>ile? ";
     GOOD$="SF"
     GOSUB 1060
     PRT=(A$="F")
     IF PRT THEN OPEN"O",2,FIL$+"LIN" ELSE OPEN"O",2,"SCRN:"
     GOTO 1100

1060 LOCATE ,,1
     A$=" "
     CALL GETKEY(GOOD$,A$)
     LOCATE ,,0
     RETURN

1100 OPEN"R",1,FIL$+"BAS"
     FIELD 1,128 AS REC$
     GET#1,1
     A$=REC$
     CLS
     PRINT"Line # cross-reference listing for ";FIL$;"BAS"
     PRINT: PRINT
     PRINT"Examining line";
     IF PRT THEN PRINT#2,"Line # cross-reference listing for ";FIL$;"BAS"
1110 IF MID$(A$,2,2)=STRING$(2,0) THEN 1340
     LN$=MID$(A$,4,2)
     LN!=CVI(LN$)
     A$=MID$(A$,6)
     IF LN!<0 THEN LN!=LN!+65536!
     LOCATE 4,15
     PRINT LN!;
1130 IF LEN(A$)<128 AND NOT EOF(1) THEN GET#1: A$=A$+REC$
     C=ASC(A$)
     IF C=0 THEN 1110
     IF C=14 THEN 1240
     IF C=34 THEN A$=MID$(A$,2): GOTO 1180
     IF C=132 OR C=143 THEN A$=MID$(A$,2): GOTO 1200
     L=2
     IF C=15 OR C>249 THEN L=3 _
     ELSE IF C=11 OR C=12 OR C=28 THEN L=4 _
     ELSE IF C=29 THEN L=6 _
     ELSE IF C=31 THEN L=10
     A$=MID$(A$,L)
     GOTO 1130
1180 IF LEN(A$)<128 AND NOT EOF(1) THEN GET#1: A$=A$+REC$
     C=ASC(A$)
     IF C=0 THEN 1110
     A$=MID$(A$,2)
     IF C=34 THEN 1130
     GOTO 1180
1200 IF LEN(A$)<128 AND NOT EOF(1) THEN GET#1: A$=A$+REC$
     C=ASC(A$)
     IF C=0 THEN QUOT=0: GOTO 1110
     L=2
     IF C=34 THEN QUOT=NOT QUOT
     IF QUOT THEN A$=MID$(A$,2): GOTO 1200
     IF C=15 OR C>249 THEN L=3 _
     ELSE IF C=11 OR C=12 OR C=28 THEN L=4 _
     ELSE IF C=29 THEN L=6 _
     ELSE IF C=31 THEN L=10
     A$=MID$(A$,L)
     GOTO 1200
1240 LNR!=CVI(MID$(A$,2,2))
     A$=MID$(A$,4)
     IF LNR!<0 THEN LNR!=LNR!+65536!
     GOSUB 1260
     GOTO 1130
1260 IF LINS=0 THEN LINS=1: LN!(1)=LNR!: LN$(1)=LN$: RETURN
     GOSUB 1290
     IF FOUND THEN GOSUB 1320: _
        IF FOUND THEN RETURN ELSE LN$(WH1)=LN$(WH1)+LN$: RETURN _
     ELSE IF LINS>499 THEN _
        PRINT: PRINT"Too many lines referenced to handle": END
     FOR X=LINS TO WH1 STEP -1
        SWAP LN!(X),LN!(X+1)
        SWAP LN$(X),LN$(X+1)
     NEXT
     LN!(WH1)=LNR!
     LN$(WH1)=LN$
     LINS=LINS+1
1290 FOUND=0
     TOP=LINS+1
     BOT=1
     OLD=-1
     WH1=LINS\2+1
     LNF!=LN!(WH1)
     WHILE OLD<>WH1 AND LNR!<>LNF!
        IF LNR!<LNF! THEN TOP=WH1 ELSE BOT=WH1
        OLD=WH1
        WH1=(TOP+BOT)\2
        LNF!=LN!(WH1)
     WEND
     IF LNR!=LNF! THEN FOUND=-1 ELSE IF LNR!>LNF! THEN WH1=WH1+1
     RETURN
1320 LNF!=CVI(RIGHT$(LN$(WH1),2))
     IF LNF!<0 THEN LNF!=65536!+LNF!
     FOUND=(LNF!=LN!)
     RETURN
1340 GOSUB 1342
     GOTO 1346
1342 CLOSE 1
     PRINT
     PRINT#2,"": PRINT#2,""
     IF PRT THEN RETURN
     PRINT"Done-- press <SPACE> for results."
     GOOD$=" "
     GOSUB 1060
     CLS
     RETURN
1346 PRINT#2,"Number of lines: ";LINS
     PRINT#2,"": PRINT#2,""
     FOR X=1 TO LINS
        LN!=LN!(X)
        GOSUB 1380
        PRINT#2," :  ";
        LN!=CVI(LEFT$(LN$(X),2))
        GOSUB 1380
        FOR Y=3 TO LEN(LN$(X)) STEP 2
           PRINT#2,", ";
           LN!=CVI(MID$(LN$(X),Y,2))
           GOSUB 1380
        NEXT
        GOSUB 1360
     NEXT
     CLOSE
     GOTO 1500
1360 IF PRT THEN PRINT#2,""
     IF NOT PRT THEN _
        IF CSRLIN<20 THEN PRINT#2,"" _
        ELSE LOCATE 25,23: PRINT"Press <SPACE> to continue listing";: _
           GOOD$=" ": GOSUB 1060: CLS
     RETURN
1380 IF LN!<0 THEN LN!=65536!+LN!
     PRINT#2,MID$(STR$(LN!),2);
     RETURN
1500 LOCATE 25,27
     PRINT"Press any key to continue";
     I$=INPUT$(1)
     GOTO 70

2000 CLEAR
2010 INPUT"File to xref";FIL$
     IF FIL$="" THEN 70
     IF FIL$="?" THEN FILES"*.BAS": GOTO 2010
     T=INSTR(FIL$,".")
     IF T THEN FIL$=LEFT$(FIL$,T) ELSE FIL$=FIL$+"."
     CALL EXIST(FIL$+"BAS"+CHR$(0),FILEXISTS)
     IF FILEXISTS=0 THEN PRINT"Missing file ";FIL$;"BAS": GOTO 2010
     OPEN"I",1,FIL$+"BAS"
     A$=INPUT$(1,1)
     CLOSE
     IF A$<>CHR$(255) THEN PRINT"Not a tokenized BASIC file.": GOTO 2010
     CALL UPCASE(FIL$)
     PRINT
     PRINT"Send results to <S>creen or <F>ile? ";
     GOOD$="SF"
     GOSUB 1060
     PRT=(A$="F")
     IF PRT THEN OPEN"O",2,FIL$+"VBL" ELSE OPEN"O",2,"SCRN:"
     OPEN"R",1,FIL$+"BAS"
     FIELD 1,128 AS REC$
     GET#1,1
     A$=REC$
     CLS
     PRINT"Variable cross-reference listing for ";FIL$;"BAS"
     PRINT: PRINT
     PRINT"Examining line";
     IF PRT THEN PRINT#2,"Variable cross-reference listing for ";FIL$;"BAS"
2110 IF MID$(A$,2,2)=STRING$(2,0) THEN 2350
     LN$=MID$(A$,4,2)
     LN!=CVI(LN$)
     A$=MID$(A$,6)
     IF LN!<0 THEN LN!=LN!+65536!
     LOCATE 4,15
     PRINT LN!;
2130 IF LEN(A$)<128 AND NOT EOF(1) THEN GET#1: A$=A$+REC$
     C=ASC(A$)
2150 IF C=0 THEN 2110
     IF C>64 AND C<91 THEN VBL$="": GOTO 2240
     IF C=34 THEN A$=MID$(A$,2): GOTO 2180
     IF C=132 OR C=143 THEN A$=MID$(A$,2): GOTO 2200
     L=2
     IF C=15 OR C>249 THEN L=3 _
     ELSE IF C=11 OR C=12 OR C=14 OR C=28 THEN L=4 _
     ELSE IF C=29 THEN L=6 _
     ELSE IF C=31 THEN L=10
2170 A$=MID$(A$,L)
     GOTO 2130
2180 IF LEN(A$)<128 AND NOT EOF(1) THEN GET#1: A$=A$+REC$
     C=ASC(A$)
     IF C=0 THEN 2110
     A$=MID$(A$,2)
     IF C=34 THEN 2130 ELSE 2180
2200 IF LEN(A$)<128 AND NOT EOF(1) THEN GET#1: A$=A$+REC$
     C=ASC(A$)
     IF C=0 THEN 2110
     L=2
     IF C=34 THEN QUOT=NOT QUOT
     IF QUOT THEN A$=MID$(A$,2): GOTO 2200
     IF C=15 OR C>249 THEN L=3 _
     ELSE IF C=11 OR C=12 OR C=28 THEN L=4 _
     ELSE IF C=29 THEN L=6 _
     ELSE IF C=31 THEN L=10
2230 A$=MID$(A$,L)
     GOTO 2200
2240 VBL$=VBL$+CHR$(C)
     A$=MID$(A$,2)
     C=ASC(A$)
     IF C>64 AND C<91 OR C>47 AND C<58 OR C=46 THEN 2240
     IF C=33 OR C>34 AND C<38 THEN VBL$=VBL$+CHR$(C): A$=MID$(A$,2): C=ASC(A$)
     IF C=40 THEN VBL$=VBL$+"()": GOSUB 2270: L=2: GOTO 2170
     GOSUB 2270
     GOTO 2150
2270 IF VBLS=0 THEN VBLS=1: VBL$(1)=VBL$: LN$(1)=LN$: RETURN
     GOSUB 2300
     IF FOUND THEN GOSUB 2330: _
        IF FOUND THEN RETURN _
        ELSE LN$(WH1)=LN$(WH1)+LN$:RETURN _
     ELSE IF VBLS>499 THEN PRINT: PRINT"Too many variables to handle": END
     FOR X=VBLS TO WH1 STEP -1
        SWAP VBL$(X),VBL$(X+1)
        SWAP LN$(X),LN$(X+1)
     NEXT
     VBL$(WH1)=VBL$
     LN$(WH1)=LN$
     VBLS=VBLS+1
2300 FOUND=0
     TOP=VBLS+1
     BOT=1
     OLD=-1
     WH1=VBLS\2+1
     VBLF$=VBL$(WH1)
     WHILE OLD<>WH1 AND VBL$<>VBLF$
        IF VBL$<VBLF$ THEN TOP=WH1 ELSE BOT=WH1
        OLD=WH1
        WH1=(TOP+BOT)\2
        VBLF$=VBL$(WH1)
     WEND
     IF VBL$=VBLF$ THEN FOUND=-1 ELSE IF VBL$>VBLF$ THEN WH1=WH1+1
     RETURN

2330 FOUND=0
     LNF!=CVI(RIGHT$(LN$(WH1),2))
     IF LNF!<0 THEN LNF!=65536!+LNF!
     FOUND=(LN!=LNF!)
     RETURN

2350 GOSUB 1342
     PRINT#2,"Number of variables: ";VBLS
     PRINT#2,"": PRINT#2,""
     FOR X=1 TO VBLS
        PRINT#2,VBL$(X);" :  ";
        LN!=CVI(LEFT$(LN$(X),2))
        GOSUB 2390
        FOR Y=3 TO LEN(LN$(X)) STEP 2
           PRINT#2,", ";
           LN!=CVI(MID$(LN$(X),Y,2))
           GOSUB 2390
        NEXT
        GOSUB 1360
     NEXT
     CLOSE
     GOTO 1500

2390 IF LN!<0 THEN LN!=65536!+LN!
     PRINT#2,MID$(STR$(LN!),2);
     RETURN
