'===========================================================================
' Subject: COLOR-CODED BASIC SOURCE VIEWER    Date: 08-05-98 (08:32)       
'  Author: Ian Smith                          Code: PB                     
'  Origin: ian@isis.demon.co.uk             Packet: MISC.ABC
'===========================================================================
'BASVIEW v1.0
'============
'
'Written in and for for PowerBASIC 3.2.
'
'BASVIEW is a colour-coded BASIC source code viewer which is supposed to make
'the structure easier to understand. The current DATA terms are for PowerBASIC,
'but changing them should be quite easy. Basically, all it does is colour the
'PB keywords, comments and quotes. The control structures have their own colour.
'
'Current limits: 5000 lines of source
'                368 keyword/highlight colour defs
'
'It was written as a teaching aid and it's very much of the "quick and dirty"
'school with no attempt at any optimization, but it may be of interest.
'
'Fingers up nose - TAB handling is a bit dodgy
'                  incomplete keyword set
'                  simplistic keyword parsing
'                  shifting right mucks up the parsing
'                  the search is case sensitive
'                  it's slow
'
'Uses some free source picked up from several places, not least the ABC
'collection.
'Getinput came from usenet, but the author is unknown to me.
'The window stuff came originally from the ABC collection and the author
'is Alexander Podkolzin (app@sbank.e-burg.su).
'I've made some modifications so any screwups are my fault.
'
'My part in this is Public Domain.       Ian Smith - ian@isis.demon.co.uk
'========================================================================
'= Compiler instructions                                                =
'========================================================================

  $CPU 8086                             'compile for 8086
  $FLOAT EMULATE                        'small and universal arithmetic
  $OPTIMIZE SPEED                       'make a fast code
  $COMPILE EXE                          'make an EXE-File
  $DEBUG MAP OFF                        'no MAP-File
  $DEBUG PBDEBUG OFF                    'no code for the debugger
  $LIB COM OFF                          'don't support COMs
  $LIB CGA OFF                          'no CGA graphics
  $LIB EGA OFF                          'no EGA graphics
  $LIB VGA OFF                          'no VGA graphics
  $LIB HERC OFF                         'no Hercules graphics
  $LIB LPT OFF                          'don't support the printer
  $LIB IPRINT OFF                       'no interpreted print
  $ERROR BOUNDS OFF                     'don't check the array bondary
  $ERROR NUMERIC OFF                    'no numeric check
  $ERROR OVERFLOW OFF                   'no overflow check
  $ERROR STACK OFF                      'don't check the stack
  $COM 0                                'communication buffer = 0
  $SOUND 1                              'smallest possible sound buffer
  $STRING 32                            '32 KByte string memory
  $OPTION CNTLBREAK OFF                 'no ctrl+break
'========================================================================
  DECLARE SUB viewsrc (filename$)
  DECLARE SUB display (aline$, shft%)
  DECLARE SUB config()
  DECLARE SUB help()
  DECLARE SUB Getinput (Srow%, Scol%, Ilen%, Ip$, Retcode%, Posn%)
  DECLARE SUB Win(t%,Title$,yb%,xb%,ye%,xe%,ct%,cb%)
  DECLARE SUB SaveScreen(w$,yb%,xb%,ye%,yx%,sh%)
  DECLARE SUB RestoreScreen(w$,yb%,xb%)
  DECLARE SUB PutAttribute(x%,y%,t%,b%)

  DEFINT A-Z
  SHARED numk%, keyword$(), colour%(), Version$
  Version$ = "1.0"
  numk% = 368                           ' If the number of DATA statements is changed, so must this
  IF DIR$(Command$) = "" THEN
     PRINT "File " + Command$ + " not found"
     END
  END IF

  config                                'read in the keyword/colour deffs
  viewsrc Command$                      'view the file in all it's glory...

  COLOR 7,0
  CLS
  END
'------------------------------------------------------------------------
  SUB viewsrc (filename$)
'       view yer actual source file in luverly colour, ducks.

     DIM lines$(5000)
     STATIC pattern$
     shft% = 1
     linecnt% = 1
     OPEN filename$ FOR INPUT AS #1     ' get the source into memory
     DO WHILE NOT EOF (1)
        LINE INPUT #1, lines$(linecnt%)
        INCR linecnt%
     LOOP
     CLOSE
     COLOR 7,1
     CLS
'  Here we go, aloopin til we drop
     DO
        IF x% > linecnt% - 24 THEN x% = linecnt% - 24
        IF y% < 25 THEN y% = 25
        IF y% > linecnt% THEN y% = linecnt%
        IF x% < 1 THEN x% = 1
        LOCATE 1, 1
        COLOR 15, 3
        PRINT " Line :"; x%; "    ": LOCATE 1, 13: PRINT SPC(45);:PRINT "F1 = Help º Version ";:PRINT Version$;
        COLOR 7, 1
        xpos% = 2
        WHILE x% < y%
           LOCATE xpos%, 1
           display lines$(x%), shft%
           INCR x%
           INCR xpos%
        WEND
        x% = x% - 24
' F-key searches and the navigation stuff.
        DO
           WHILE INKEY$ <> "": WEND     ' empty buffer
           DO
              pressed$ = INKEY$
           LOOP UNTIL pressed$ <> ""
           SELECT CASE pressed$
              CASE CHR$(0, 61)          ' F3 - search again
                 n% = x% + 1
                 DO WHILE n% < linecnt%
                    IF TALLY (lines$(n%),pattern$) > 0 then
                       x% = n%
                       y% = x% + 24
                       tgt% = n%
                       EXIT DO
                    END IF
                    INCR n%
                 LOOP
                 IF n% = linecnt% THEN LOCATE 1,30:COLOR 0,3:PRINT "string not found !"
                 IF n% < linecnt% THEN EXIT DO

              CASE CHR$(0, 60)          ' F2 - search for word
                 savescreen helpscreen$,7,19,9,57,1
                 win 1,"Search",7,19,9,57,0,3
                 LOCATE 8,21: COLOR 15,3:PRINT "Search String:";
                 pattern$ = ""
                 COLOR 1,3: Getinput 8,36, 20, pattern$,0,0
                 restorescreen helpscreen$,7,19
                 LOCATE ,,0             ' hide the cursor
                 IF pattern$ <> "" THEN
                    n% = x%
                    DO WHILE n% < linecnt%
                       IF TALLY (lines$(n%),pattern$) > 0 THEN
                          x% = n%
                          y% = x% + 24
                          tgt% = n%
                          EXIT DO
                       END IF
                       INCR n%
                    LOOP
                    IF n% = linecnt% THEN LOCATE 1,30:COLOR 0,3:PRINT "string not found !"
                    IF n% < linecnt% THEN EXIT DO
                 END IF
              CASE CHR$(0, 59)          ' F1 - help
                 help
              CASE CHR$(0, 71)          'home
                 x% = 1
                 y% = 24
                 EXIT DO
              CASE CHR$(0, 79)          'end
                 x% = linecnt% - 24
                 y% = linecnt% + 1
                 EXIT DO
              CASE CHR$(0, 72)          'up
                 DECR x%
                 DECR y%
                 EXIT DO
              CASE CHR$(0, 73)          'Pg up
                 x% = x% - 24
                 y% = y% - 24
                 EXIT DO
              CASE CHR$(0, 80)          'down
                 INCR x
                 INCR y
                 EXIT DO
              'Pg down, SPACE, TAB
              CASE CHR$(0, 81), CHR$(32), CHR$(9)
                 x% = x% + 24
                 y% = y% + 24
                 EXIT DO
              CASE CHR$(27)             ' Esc quit
                 quit% = 1
                 EXIT DO
              CASE CHR$(0, 77)          'right
                 INCR shft%
                 EXIT DO
              CASE CHR$(0, 75)          'left
                 DECR shft%
                 IF shft% < 1 THEN shft% = 1
                 EXIT DO
              CASE ELSE
                 EXIT DO
           END SELECT
        LOOP
        IF quit% = 1 THEN EXIT DO
     LOOP
  END SUB
'------------------------------------------------------------------------
  SUB display (aline$, shft%)
' display a line of code

     COLOR 7,1
     comment% = 0
     quote% = 0
     el% = LEN(aline$) + 1
     FOR cp% = shft% TO shft% + 79
        ltr$ = MID$(aline$, cp%, 1)
        IF cp% < el% THEN
           IF comment% = 0 THEN
              IF ltr$ = CHR$(34) THEN
                 IF quote% = 0 THEN
                    quote% = 1
                    COLOR 13,1
                 ELSE
                    quote% = 3
                 END IF
              ELSEIF quote% = 0 AND INSTR(ltr$, ANY ":,;, ,(,),+,-,="+ CHR$(9)) THEN
                 COLOR 7,1
                 word% = 0
              ELSE
                 IF word% = 0 AND quote% = 0 THEN
                    eow% = INSTR(cp%, aline$, ANY ":,;, ,(,),+,-,="+CHR$(9))
                    IF eow% = 0 AND cp% =< LEN(aline$) THEN eow% = LEN(aline$) + 1
                    testkey$ = MID$(aline$, cp%, eow% - cp%)
                    word% = 1
                    IF LEFT$(testkey$,1) = "'" OR LCASE$(testkey$) = "rem" THEN comment% = 1: COLOR 3, 1
                    FOR n% = 1 TO numk%
                       IF LCASE$(testkey$) = keyword$(n%) THEN
                          COLOR colour%(n%), 1
                          EXIT FOR
                       END IF
                    NEXT
                 END IF
              END IF
           END IF
           IF ltr$ = CHR$(9) THEN
              PRINT TAB(8*(POS(0)/8 + 1))
           ELSE
              IF POS(0) < 80 THEN PRINT ltr$;
              IF quote% = 3 THEN quote% = 0: COLOR 7,1
           END IF
        ELSE
           IF POS(0) < 80 THEN PRINT " ";
        END IF
     NEXT
  END SUB
'------------------------------------------------------------------------
  SUB config
'reads the DATA statements

     DIM keyword$(numk%), colour%(numk%)
     FOR n% = 1 TO numk%
        READ keyword$(n%)
        READ colour%(n%)
     NEXT
  END SUB
'------------------------------------------------------------------------
  SUB help
'Help window

     Savescreen helpscreen$,5,16,15,65,1
     Win 2,"Help !",5,16,15,65,14,3
     COLOR 1,3
     LOCATE 6,31: PRINT "BASVIEW source viewer";
     COLOR 0,3
     LOCATE 7,18: PRINT "Navigation:";
     LOCATE 8,18: PRINT "Up/Down arrow keys     move one line";
     LOCATE 9,18: PRINT "PgUp/PgDn(or SPACE)    move one screen";
     LOCATE 10,18: PRINT "Left/Right arrow keys  shift 5 columns";
     LOCATE 11,18: PRINT "Home                   goes to top of file";
     LOCATE 12,18: PRINT "End                    goes to bottom of file";
     COLOR 4,3
     LOCATE 13,18: PRINT "F2 asks for search string, F3 repeats search";
     LOCATE 14,18: PRINT "Esc Exits the viewer";
     WHILE INKEY$ = ""
     WEND
     Restorescreen helpscreen$,5,16
  END SUB
'------------------------------------------------------------------------
' Sub Program to handle window input
'  (Displays existing value of variable and allows changes to it)
'  (Terminates by Enter,Esc,FunKey,UP/Down Arrow etc)
'   Parameters are:
'   srow%,scol% - location of start of string input
'         ilen% - maximum number of characters to accept
'           ip$ - variable to accept input into
'      retcode% - records which terminating key was pressed by user
'         posn% - cursor location when terminating key pressed
' =======================================================================
  Sub Getinput (Srow%, Scol%, Ilen%, Ip$, Retcode%, Posn%)
     B$ = Space$(Ilen%)
     Posn% = 1
     Retcode% = 0
     While Retcode% < 1
        Locate Srow%, Scol%: Print Left$(Ip$ + B$, Ilen%)
        Locate Srow%, Scol% - 1 + Posn%, 1, 7, 7
        A$="": While A$ = "": A$ = Inkey$: Wend
        Select Case A$
           Case " " To Chr$(255)        'Normal Key
              If Posn% > Ilen% Then Posn% = Ilen%
              If Posn% <= Len(Ip$) Then Mid$(Ip$, Posn%, 1) = A$ Else Ip$ = Ip$ + A$
              Posn% = Posn% + 1: If Posn% > Ilen% Then Posn% = Ilen%

           Case Chr$(8)                 'Backspace
              If Posn% > 1 Then
                 Temp1$ = Left$(Ip$, Posn% - 2)
                 Temp2$ = Mid$(Ip$, Posn%)
                 Ip$ = Temp1$ + Temp2$
                 Posn% = Posn% - 1
              End If
           Case Chr$(0) + Chr$(83)      'Delete Key
              Temp1$ = Left$(Ip$, Posn% - 1)
              Temp2$ = Mid$(Ip$, Posn% + 1)
              Ip$ = Temp1$ + Temp2$
           Case Chr$(0) + Chr$(75)      'Leftarrow
              Posn% = Posn% - 1: If Posn% < 1 Then Posn% = 1
           Case Chr$(0) + Chr$(77)      ' Rightarrow
              Posn% = Posn% + 1: If Posn% > Len(Ip$) Then Posn% = Len(Ip$)

           Case Chr$(27)                'Escape
              Retcode% = 99
           Case Chr$(13)                'Return
              Retcode% = 98
           Case Chr$(0) + Chr$(80)      'Downarrow
              Retcode% = 97
           Case Chr$(0) + Chr$(72)      'Uparrow
              Retcode% = 96
           Case Chr$(0) + Chr$(59)      'F1
              Retcode% = 1
           Case Chr$(0) + Chr$(60)      'F2
              Retcode% = 2
           Case Chr$(0) + Chr$(61)      'F3
              Retcode% = 3
           Case Chr$(0) + Chr$(62)      'F4
              Retcode% = 4
           Case Chr$(0) + Chr$(63)      'F5
              Retcode% = 5
           Case Chr$(0) + Chr$(64)      'F6
              Retcode% = 6
           Case Chr$(0) + Chr$(65)      'F7
              Retcode% = 7
           Case Chr$(0) + Chr$(66)      'F8
              Retcode% = 8
           Case Chr$(0) + Chr$(67)      'F9
              Retcode% = 9
           Case Chr$(0) + Chr$(68)      'F10
              Retcode% = 10
           Case Else                    ' All Other Keys
              Beep
        End Select
     Wend
  End Sub
'--------------------------------------------------------------------------
' Sub Win(t%,Title$,yb%,xb%,ye%,xe%,ct%,cb%)
' Parameters:
' t%               - the window type,
' Title$           - window title,
' yb%,xb%,ye%,xe%  - the window coordinates,
'             ct%  - text color,
'             cb%  - background color of the window;
'--------------------------------------------------------------------------
  SUB Win(t%,Title$,yb%,xb%,ye%,xe%,ct%,cb%)
'
     OldColor% = pbvScrnTxtAttr         ' Internal PB variable
'
     SELECT CASE t%                     ' Window types
'                                       ' (you can make as much types,
'                                       '  as you want):
        CASE 1
           'ÚÄ´ÃÄÄÄÄ¿ ´Ã
           a%=218:b%=196:c%=191:i%=180:j%=195
           h%=179: :d%=179              '³   1   ³
           g%=192:f%=196:e%=217         'ÀÄÄÄÄÄÄÄÙ
        CASE 2
           'ÉÍµÆÍÍÍÍ» µÆ
           a%=201:b%=205:c%=187:i%=181:j%=198
           h%=186: :d%=186              'º   2   º
           g%=200:f%=205:e%=188         'ÈÍÍÍÍÍÍÍ¼
        CASE ELSE
           a%=032:b%= a%:c%= a%         '
           h%= a%: :d%= a%              ' Blanks only
           g%= a%:f%= a%:e%= a%         '
     END SELECT
     COLOR ct%,cb%
     LOCATE yb%,xb%

      ' draw the window
       ' top line with title, if provided
     IF LEN(Title$) THEN
        Title$ = " " + Title$ + " "
        x% = ((xe% - xb%) - 1) - (LEN(Title$) + 2)
        y% = x% \ 2
        z% = x% - y%
        Ti$ = STRING$(y%,CHR$(b%)) + CHR$(i%) + Title$ + CHR$(j%) + STRING$(z%,CHR$(b%))
        PRINT CHR$(a%) + Ti$ + CHR$(c%);
     ELSE
        PRINT CHR$(ac%) + W$ + CHR$(c%);
     END IF
  ' middle
     FOR i%=yb%+1 TO ye%-1
        LOCATE i%,xb% : PRINT CHR$(h%)+ SPACE$(xe%-xb%-1) +CHR$(d%)
     NEXT
       ' bottom
     LOCATE ye%,xb% : PRINT CHR$(g%)+REPEAT$(xe%-xb%-1,CHR$(f%))+CHR$(e%)

     FOR i%=yb%+1 TO ye%+1
        PutAttribute xe%+1,i%,7,0       ' Making
     NEXT                               ' shadows
     FOR i%=xb%+1 TO xe%+1              '
        PutAttribute i%,ye%+1,7,0       '
     NEXT
     ct%=OldColor% AND 15               ' restore colors
     cb%=OldColor%\16
     COLOR ct%,cb%
  END SUB
'-------------------------------------------------------------------------
' Sub SaveScreen(w$,yb%,xb%,ye%,xe%,sh%)
' Parameters:
' w$               - string to save window in,
' yb%,xb%,ye%,xe%  - the window coordinates,
'             sh%  - shadow,
'
'-------------------------------------------------------------------------
  SUB SaveScreen(w$,yb%,xb%,ye%,xe%,sh%) PUBLIC
     DIM temp AS BYTE PTR
     DIM WinPtr AS BYTE PTR
     DIM TextPtr AS BYTE PTR
     lx% = (xe% - xb% + 1) * 2
     ly% = ye% - yb% + 1
     IF sh% THEN
        INCR lx%,2
        INCR ly%
     END IF
     l$ = RIGHT$(" " + STR$(lx%), 3 )
     w$ = l$ + SPACE$( lx% * ly% )
     WinPtr = PBVSCRNBUFF + (yb%-1)*160 + (xb%-1)*2
     TextPtr = STRPTR32(w$) + 3
     FOR i%=1 TO ly%
        temp = WinPtr
        FOR k%=1 TO lx%
           @TextPtr = @temp
           INCR TextPtr
           INCR temp
        NEXT
        INCR WinPtr,160
     NEXT
  END SUB
'-------------------------------------------------------------------------
' Sub RestoreScreen(w$,yb%,xb%)
' Parameters:
' w$               - string holding saved window data,
' yb%,xb%,ye%,xe%  - the window coordinates,
'-------------------------------------------------------------------------
  SUB RestoreScreen(w$,yb%,xb%) PUBLIC
     DIM temp AS BYTE PTR
     DIM WinPtr AS BYTE PTR
     DIM TextPtr AS BYTE PTR
     l$ = LEFT$(w$,3)
     w$ = LTRIM$(w$,l$)
     lx% = VAL(l$)
     ly% = LEN(w$) \ lx%
     TextPtr = STRPTR32(w$)
     WinPtr = PBVSCRNBUFF + (yb%-1)*160 + (xb%-1)*2
     FOR i%=1 TO ly%
        temp = WinPtr
        FOR k%=1 TO lx%
           @temp = @TextPtr
           INCR TextPtr
           INCR temp
        NEXT
        INCR WinPtr,160
     NEXT
  END SUB

'--------------------------------------------------------------------------
  SUB PutAttribute(x%,y%,t%,b%)         ' Puts attribute byte to video memory
     LOCAL c%                           ' directly to Colomn, Row position
     c% = b%*16+t%                      '
     DEF SEG = &hb800                   ' NOTE: This is system depending !
     POKE 160*(y%-1)+x%+x%-1,c%
     DEF SEG
  END SUB
'--------------------------------------------------------------------------
  DATA if,14,then,14,end,14,else,14,for,14,next,14,elseif,14,while,14,wend,14,do,14,loop,14,until,14,case,14,select,14,to,14,incr,11,decr,11,print,11,line,11,color,11,declare,11,dim,11,locate,11,delay,11,cls,11,shared,11,call,11,open,11
  DATA input,11,output,11,as,11,get,11,chr$,11,mid$,11,str$,11,left$,11,right$,11,sub,15,function,15,$alias,10,$code,10,$com,10,$compile,10,$cpu,10,$debug,10,$dim,10,$dynamic,10,$error,10,$event,10,$float,10,$huge,10,$if,10,$else,10,$endif,10
  DATA $include,10,$inline,10,$lib,10,$link,10,$optimize,10,$option,10,$segment,10,$sound,10,$stack,10,$static,10,$string,10,abs,11,absolute,11,access,11,and,11,any,11,append,11,array,11,asc,11,ascend,11,ascii,11,asm,11,atn,11,attrib,11,base,11
  DATA beep,11,bin$,11,binary,11,bit,11,bits,11,bload,11,bsave,11,ceil,11,chain,14,chdir,11,chdrive,11,cint,11,clng,11,cqud,11,csng,11,cdbl,11,cext,11,cfix,11,cbcd,11,cbyt,11,cwrd,11,cdwd,11,circle,11,clear,11,close,11,codeptr,11,codeseg,11
  DATA collaate,11,color,11,com,11,command$,11,common,11,cos,11,csrlin,11,curdir$,11,cvi,11,cvl,11,cvq,11,cvs,11,cvd,11,cve,11,cvf,11,cvb,11,cvbyt,11,cvdwd,11,cvwrd,11,cvmd,11,cvms,11,data,11,date$,11,def,11,deflng,11,defqud,11,defsng,11
  DATA defdbl,11,deefext,11,deffix,11,defbcd,11,defstr,11,defflx,11,delete,11,descend,11,dir$,11,draw,11,dynamic,11,ems,11,endmem,11,environ,11,environ$,11,eof,11,eqv,11,eradr,11,erase,11,erdev,11,erdev$,11,erl,11,err,11,error,11,errtest,11
  DATA execute,11,exit,14,exp,11,exp10,11,exp2,11,external,11,extract$,11,far,11,field,11,fileattr,11,files,11,fixdigits,11,flexchr$,11,flush,11,fn,11,step,11,frac,11,fre,11,freefile,11,from,11,get$,11,gosub,11,goto,11,hex$,11,imp,11,in,11
  DATA inkey$,11,inp,11,input$,11,insert,11,instat,11,instr,11,int,11,interrupt,11,ioctl,11,ioctl$,11,isfalse,11,istrue,11,iterate,11,key,11,kill,11,lbound,11,lcase$,11,left$,11,len,11,let,11,line,11,list,11,loc,11,local,11,locate,11,lock,11
  DATA lof,11,log,11,log10,11,log2,11,lpos,11,lprint,11,lset,11,ltrim$,11,map,11,max,11,max$,11,max%,11,mempack,11,memset,11,mid$,11,min,11,min$,11,min%,11,mkdir,11,mki$,11,mkl$,11,mkq$,11,mks$,11,mkd$,11,mke$,11,mkf$,11,mkb$,11,mkbyt$,11
  DATA mkwrd$,11,mkdwd$,11,mkmd$,11,mkms$,11,mtimer,11,multiplex,11,name,11,not,11,oct$,11,off,11,on,11,open,11,option,11,or,11,out,11,output,11,paint,11,palette,11,peek,11,peek$,11,peeki,11,peekl,11,pen,11,play,11,pmap,11,point,11
  DATA poke,11,poke$,11,pokei,11,pokel,11,popup,11,pos,11,preset,11,pset,11,public,11,put,11,put$,11,quiet,11,random,11,randomize,11,read,11,redim,11,reg,11,remove$,11,repeat$,11,replace,11,reset,11,restore,11,resume,11,return,11,right,11
  DATA rmdir,11,rnd,11,rotate,11,round,11,rset,11,rtrim$,11,run,11,scan,11,screen,11,seek,11,seg,11,setmem,11,sgn,11,shared,11,shell,11,shift,11,signed,11,sin,11,sleep,11,sort,11,sound,11,space$,11,spc,11,sqr,11,static,11,stick,11,stop,11
  DATA str$,11,strig,11,string$,11,strptr,11,strseg,11,stuff,11,swap,11,system,11,tab,11,tagarray,11,tally,11,tan,11,time$,11,timer,11,troff,11,tron,11,type,11,ubound,11,ucase,11,ucase$,11,uevent,11,union,11,unlock,11,using,11,using$,11,val,11
  DATA varptr,11,varptr$,11,varseg,11,verify,11,view,11,wait,11,width,11,window,11,with,11,write,11,xor,11,integer,11,long,11,quad,11,byte,11,word,11,dword,11,single,11,double,11,ext,11,fix,11,bcd,11,string,11,flex,11,byval,11,defint,11
