Added src.
authorblitz-research <blitzmunter@gamil.com>
Wed, 22 Jan 2014 22:34:04 +0000 (11:34 +1300)
committerblitz-research <blitzmunter@gamil.com>
Wed, 22 Jan 2014 22:34:04 +0000 (11:34 +1300)
50 files changed:
src/bmk/bmk.bmx [new file with mode: 0644]
src/bmk/bmk_bank.bmx [new file with mode: 0644]
src/bmk/bmk_bb2bmx.bmx [new file with mode: 0644]
src/bmk/bmk_config.bmx [new file with mode: 0644]
src/bmk/bmk_make.bmx [new file with mode: 0644]
src/bmk/bmk_modinfo.bmx [new file with mode: 0644]
src/bmk/bmk_modutil.bmx [new file with mode: 0644]
src/bmk/bmk_util.bmx [new file with mode: 0644]
src/bmk/bmk_zap.bmx [new file with mode: 0644]
src/bmk/macos.icns [new file with mode: 0644]
src/docmods/bmxtoker.bmx [new file with mode: 0644]
src/docmods/dochistory.bmx [new file with mode: 0644]
src/docmods/docmods.bmx [new file with mode: 0644]
src/docmods/docparser.bmx [new file with mode: 0644]
src/fasm2as/fasm2as.bmx [new file with mode: 0644]
src/makedocs/bbdoc.bmx [new file with mode: 0644]
src/makedocs/docnode.bmx [new file with mode: 0644]
src/makedocs/docstyle.bmx [new file with mode: 0644]
src/makedocs/fredborgstyle.bmx [new file with mode: 0644]
src/makedocs/makedocs.bmx [new file with mode: 0644]
src/makedocs/parse.bmx [new file with mode: 0644]
src/makedocs/readme.txt [new file with mode: 0644]
src/maxide/Info.plist [new file with mode: 0644]
src/maxide/bmxlogo.png [new file with mode: 0644]
src/maxide/default.language.ini [new file with mode: 0644]
src/maxide/makeicons/Back.png [new file with mode: 0644]
src/maxide/makeicons/Build-Run.png [new file with mode: 0644]
src/maxide/makeicons/Build.png [new file with mode: 0644]
src/maxide/makeicons/Close.png [new file with mode: 0644]
src/maxide/makeicons/Copy.png [new file with mode: 0644]
src/maxide/makeicons/Cut.png [new file with mode: 0644]
src/maxide/makeicons/Find.png [new file with mode: 0644]
src/maxide/makeicons/Forward.png [new file with mode: 0644]
src/maxide/makeicons/Go.png [new file with mode: 0644]
src/maxide/makeicons/Home.png [new file with mode: 0644]
src/maxide/makeicons/New.png [new file with mode: 0644]
src/maxide/makeicons/Open.png [new file with mode: 0644]
src/maxide/makeicons/Paste.png [new file with mode: 0644]
src/maxide/makeicons/Save.png [new file with mode: 0644]
src/maxide/makeicons/Step-In.png [new file with mode: 0644]
src/maxide/makeicons/Step-Out.png [new file with mode: 0644]
src/maxide/makeicons/Step.png [new file with mode: 0644]
src/maxide/makeicons/Stop.png [new file with mode: 0644]
src/maxide/makeicons/makeicons.bmx [new file with mode: 0644]
src/maxide/maxicons.o [new file with mode: 0644]
src/maxide/maxide.bmx [new file with mode: 0644]
src/maxide/readme.txt [new file with mode: 0644]
src/maxide/splash.png [new file with mode: 0644]
src/maxide/toolbar.png [new file with mode: 0644]
src/maxide/window_icon.png [new file with mode: 0644]

diff --git a/src/bmk/bmk.bmx b/src/bmk/bmk.bmx
new file mode 100644 (file)
index 0000000..e0ab2e8
--- /dev/null
@@ -0,0 +1,317 @@
+'
+' Change History :
+'  BaH 28/09/2007 - Added custom appstub compiles using -b parameter.
+'                   Synched with current bmk source.
+'
+Strict
+
+Framework brl.basic
+
+Import "bmk_make.bmx"
+Import "bmk_zap.bmx"
+Import "bmk_bb2bmx.bmx"
+
+?MacOS
+Incbin "macos.icns"
+?
+
+If AppArgs.length<2 CmdError
+
+Local cmd$=AppArgs[1],args$[]
+
+args=ParseConfigArgs( AppArgs[2..] )
+
+CreateDir BlitzMaxPath()+"/tmp"
+
+Select cmd.ToLower()
+Case "makeapp"
+       SetConfigMung
+       MakeApplication args,False
+Case "makelib"
+       SetConfigMung
+       MakeApplication args,True
+Case "makemods"
+'      Local ms=MilliSecs()
+       If opt_debug Or opt_release
+               SetConfigMung
+               MakeModules args
+       Else
+               opt_debug=True
+               opt_release=False
+               SetConfigMung
+               MakeModules args
+               opt_debug=False
+               opt_release=True
+               SetConfigMung
+               MakeModules args
+       EndIf
+'      ms=MilliSecs()-ms
+'      Print "ms="+ms
+Case "cleanmods"
+       CleanModules args
+Case "zapmod"
+       ZapModule args
+Case "unzapmod"
+       UnzapModule args
+Case "listmods"
+       ListModules args
+Case "modstatus"
+       ModuleStatus args
+Case "syncmods" 
+       SyncModules args
+Case "convertbb"
+       ConvertBB args
+Case "ranlibdir"
+       RanlibDir args
+Default
+       CmdError
+End Select
+
+Function SetConfigMung()
+       If opt_release
+               opt_debug=False
+               opt_configmung="release"
+               If opt_threaded opt_configmung:+".mt"
+               opt_configmung="."+opt_configmung+"."+cfg_platform+"."+opt_arch
+       Else
+               opt_debug=True
+               opt_release=False
+               opt_configmung="debug"
+               If opt_threaded opt_configmung:+".mt"
+               opt_configmung="."+opt_configmung+"."+cfg_platform+"."+opt_arch
+       EndIf
+End Function
+
+Function SetModfilter( t$ )
+
+       opt_modfilter=t.ToLower()
+
+       If opt_modfilter="*"
+               opt_modfilter=""
+       Else If opt_modfilter[opt_modfilter.length-1]<>"." 
+               opt_modfilter:+"."
+       EndIf
+       
+End Function
+
+Function MakeModules( args$[] )
+
+       If args.length>1 CmdError
+       
+       If args.length SetModfilter args[0] Else opt_modfilter=""
+       
+       Local mods:TList=EnumModules()
+       
+       BeginMake
+
+       MakeMod "brl.blitz"
+       
+       For Local name$=EachIn mods
+               MakeMod name
+       Next
+       
+End Function
+
+Function CleanModules( args$[] )
+
+       If args.length>1 CmdError
+       
+       If args.length SetModfilter args[0] Else opt_modfilter=""
+       
+       Local mods:TList=EnumModules()
+
+       Local name$
+       For name=EachIn mods
+       
+               If (name+".").Find(opt_modfilter)<>0 Continue
+               
+               Print "Cleaning:"+name
+
+               Local path$=ModulePath(name)
+               
+               DeleteDir path+"/.bmx",True
+               
+               If Not opt_kill Continue
+               
+               For Local f$=EachIn LoadDir( path )
+               
+                       Local p$=path+"/"+f
+                       Select FileType(p)
+                       Case FILETYPE_DIR
+                               If f<>"doc"
+                                       DeleteDir p,True
+                               EndIf
+                       Case FILETYPE_FILE
+                               Select ExtractExt(f).tolower()
+                               Case "i","a","txt","htm","html"
+                                       'nop
+                               Default
+                                       DeleteFile p
+                               End Select
+                       End Select
+
+               Next
+       Next
+
+End Function
+
+Function MakeApplication( args$[],makelib )
+       If opt_execute
+               If Len(args)=0 CmdError
+       Else
+               If Len(args)<>1 CmdError
+       EndIf
+
+       Local Main$=RealPath( args[0] )
+       
+       Select ExtractExt(Main).ToLower()
+       Case ""
+               Main:+".bmx"
+       Case "c","cpp","cxx","mm","bmx"
+       Default
+               Throw "Unrecognized app source file type:"+ExtractExt(Main)
+       End Select
+
+       If FileType(Main)<>FILETYPE_FILE Throw "Unable to open source file '"+Main+"'"
+       
+       If Not opt_outfile opt_outfile=StripExt( Main )
+
+?Win32
+       If makelib
+               If ExtractExt(opt_outfile).ToLower()<>"dll" opt_outfile:+".dll"
+       Else
+               If ExtractExt(opt_outfile).ToLower()<>"exe" opt_outfile:+".exe"
+       EndIf
+?
+
+?MacOS
+       If opt_apptype="gui"
+
+               Local appId$=StripDir( opt_outfile )
+
+               Local exeDir$=opt_outfile+".app",d$,t:TStream
+
+               d=exeDir+"/Contents/MacOS"
+               Select FileType( d )
+               Case FILETYPE_NONE
+                       CreateDir d,True
+                       If FileType( d )<>FILETYPE_DIR
+                               Throw "Unable to create application directory"
+                       EndIf
+               Case FILETYPE_FILE
+                       Throw "Unable to create application directory"
+               Case FILETYPE_DIR
+               End Select
+               
+               d=exeDir+"/Contents/Resources"
+               Select FileType( d )
+               Case FILETYPE_NONE
+                       CreateDir d
+                       If FileType( d )<>FILETYPE_DIR
+                               Throw "Unable to create resources directory"
+                       EndIf
+               Case FILETYPE_FILE
+                       Throw "Unable to create resources directory"
+               Case FILETYPE_DIR
+               End Select
+
+               t=WriteStream( exeDir+"/Contents/Info.plist" )
+               If Not t Throw "Unable to create Info.plist"
+               t.WriteLine "<?xml version=~q1.0~q encoding=~qUTF-8~q?>"
+               t.WriteLine "<!DOCTYPE plist PUBLIC ~q-//Apple Computer//DTD PLIST 1.0//EN~q ~qhttp://www.apple.com/DTDs/PropertyList-1.0.dtd~q>"
+               t.WriteLine "<plist version=~q1.0~q>"
+               t.WriteLine "<dict>"
+               t.WriteLine "~t<key>CFBundleExecutable</key>"
+               t.WriteLine "~t<string>"+appId+"</string>"
+               t.WriteLine "~t<key>CFBundleIconFile</key>"
+               t.WriteLine "~t<string>"+appId+"</string>"
+               t.WriteLine "~t<key>CFBundlePackageType</key>"
+               t.WriteLine "~t<string>APPL</string>"
+               t.WriteLine "</dict>"
+               t.WriteLine "</plist>"
+               t.Close
+
+               t=WriteStream( exeDir+"/Contents/Resources/"+appId+".icns" )
+               If Not t Throw "Unable to create icons"
+               Local in:TStream=ReadStream( "incbin::macos.icns" )
+               CopyStream in,t
+               in.Close
+               t.Close
+               
+               opt_outfile=exeDir+"/Contents/MacOS/"+appId
+               
+       EndIf
+?
+       BeginMake
+       
+       MakeApp Main,makelib
+       
+       If opt_execute
+
+               Print "Executing:"+StripDir( opt_outfile )
+
+               Local cmd$=CQuote( opt_outfile )
+               For Local i=1 Until args.length
+                       cmd:+" "+CQuote( args[i] )
+               Next
+               
+               Sys cmd
+               
+       EndIf
+
+End Function
+
+Function ZapModule( args$[] )
+       If Len(args)<>2 CmdError
+
+       Local modname$=args[0].ToLower()
+       Local outfile$=RealPath( args[1] )
+
+       Local stream:TStream=WriteStream( outfile )
+       If Not stream Throw "Unable to open output file"
+       
+       ZapMod modname,stream
+       
+       stream.Close
+End Function
+
+Function UnzapModule( args$[] )
+       If Len(args)<>1 CmdError
+       
+       Local infile$=args[0]
+       
+       Local stream:TStream=ReadStream( infile )
+       If Not stream Throw "Unable to open input file"
+       
+       UnzapMod stream
+       
+       stream.Close
+End Function
+
+Function ListModules( args$[],modid$="" )
+       If Len(args)<>0 CmdError
+       
+       Throw "Todo!"
+
+End Function
+
+Function ModuleStatus( args$[] )
+       If Len(args)<>1 CmdError
+       
+       ListModules Null,args[0]
+
+End Function
+
+Function SyncModules( args$[] )
+       If args.length CmdError
+       
+       If Sys( BlitzMaxPath()+"/bin/syncmods" ) Throw "SyncMods error"
+       
+End Function
+
+Function RanlibDir( args$[] )
+       If args.length<>1 CmdError
+       
+       Ranlib args[0]
+
+End Function
diff --git a/src/bmk/bmk_bank.bmx b/src/bmk/bmk_bank.bmx
new file mode 100644 (file)
index 0000000..917b66e
--- /dev/null
@@ -0,0 +1,122 @@
+
+Strict
+
+Import "bmk_config.bmx"
+
+Import Pub.ZLib
+
+Function CompressBank:TBank( bank:TBank )
+
+       Local size=bank.Size()
+       Local out_size=size+size/10+32
+       Local out:TBank=TBank.Create( out_size )
+       compress out.Buf()+4,out_size,bank.Buf(),size
+       out.PokeByte 0,size
+       out.PokeByte 1,size Shr 8
+       out.PokeByte 2,size Shr 16
+       out.PokeByte 3,size Shr 24
+       out.Resize out_size+4
+       Return out
+
+End Function
+
+Function UncompressBank:TBank( bank:TBank )
+
+       Local out_size
+       out_size:|bank.PeekByte(0)
+       out_size:|bank.PeekByte(1) Shl 8
+       out_size:|bank.PeekByte(2) Shl 16
+       out_size:|bank.PeekByte(3) Shl 24
+       Local out:TBank=TBank.Create( out_size )
+       uncompress out.Buf(),out_size,bank.Buf()+4,bank.Size()-4
+       Return out
+       
+End Function
+
+Function SplitUrl( url$,server$ Var,file$ Var )
+       Local i=url.Find( "/",0 )
+       If i<>-1
+               server=url[..i]
+               file=url[i..]
+       Else
+               server=url
+               file="/"
+       EndIf
+End Function
+
+Function HTTPGetBank:TBank( url$ )
+
+       Local server$,file$
+       SplitUrl url,server,file
+       
+       Local t_server$=server
+       If opt_proxy t_server=opt_proxy
+
+       Local t_port=80
+       If opt_proxyport t_port=opt_proxyport
+       
+       Local stream:TStream=TSocketStream.CreateClient( t_server,t_port )
+       If Not stream Return
+       
+       stream.WriteLine "GET http://"+url+" HTTP/1.0"
+       stream.WriteLine "Host: "+server
+       stream.WriteLine ""
+               
+       While Not stream.Eof()
+               Local t$=stream.ReadLine()
+               If Not t Exit
+       Wend
+       
+       Local bank:TBank=TBank.Create(0)
+       Local bank_stream:TStream=TBankStream.Create( bank )
+       
+       CopyStream stream,bank_stream
+       
+       bank_stream.Close
+       stream.Close
+       
+       Return bank
+       
+End Function
+
+Function HTTPPostBank$( bank:TBank,url$ )
+
+       Local server$,file$
+       SplitUrl url,server,file
+               
+       Local t_server$=server
+       If opt_proxy t_server=opt_proxy
+
+       Local t_port=80
+       If opt_proxyport t_port=opt_proxyport
+
+       Local stream:TStream=TSocketStream.CreateClient( t_server,t_port )
+       If Not stream Return
+               
+       stream.WriteLine "POST http://"+url+" HTTP/1.0"
+       stream.WriteLine "Host: "+server
+       stream.WriteLine "Content-Type: application/octet-stream"
+       stream.WriteLine "Content-Length: "+bank.Size()
+       stream.WriteLine ""
+       
+       Local bank_stream:TStream=TBankStream.Create( bank )
+       CopyStream bank_stream,stream
+       bank_stream.Close
+       
+       While Not stream.Eof()
+               Local t$=stream.ReadLine()
+               If Not t Exit
+       Wend
+       
+       Local r$
+       While Not stream.Eof()
+               Local t$=stream.ReadLine()
+               r:+t+"~n"
+       Wend
+       
+       stream.Close
+       
+       Return r
+
+End Function
+
diff --git a/src/bmk/bmk_bb2bmx.bmx b/src/bmk/bmk_bb2bmx.bmx
new file mode 100644 (file)
index 0000000..daf57ff
--- /dev/null
@@ -0,0 +1,758 @@
+
+Strict
+
+' bmk_bb2bmx.bmx v0.4
+' by simonarmstrong@blitzbasic.com
+
+' converts BlitzBasic source files to BlitzMax
+
+' history
+
+' AND OR operators -> bitwise if not followed by conditional operators =<>  
+' Min and Max -> _Min and _Max
+' HandleFromObject and HandleToObject added to bbtype.bmx 
+' link and list fields in bbtype -> _link and _list
+' IncrementArrays$(code$) adds 1 to all array dimensions of array declarations
+' ReadString(TStream) function added and FreeSound(sound)->Release(sound)
+' hidepointer -> hidemouse showpointer -> showmouse
+' delete obj -> obj.remove
+' readpixel->dev.blitz3d.readpixel writepixel->dev.blitz3d.writepixel
+' seekfile -> seekstream  filepos -> streampos
+' channelvolume->SetChannelVolume soundvolume->
+' readbytes -> ReadBank writebytes-> WriteBankq
+' xor->~ getkey->waitkey mousewait->waitmouse
+' handle -> HandleFromObject object -> HandleToObject
+' stop -> DebugStop
+' .label -> #label
+' param[n]->param[] in function declarations
+' added TypePrefix$ to help avoid type name / variable name clashes
+' processes include files
+' output bbtype.bmx and bbvkey.bmx files (thanks to Terabit) 
+' moved to bmk_bb2bmx
+' inline comments replace ; with '
+' command separators replace : with ;
+' type specifiers replace . with :
+' field separators replace \ with .
+' boolean operators replace and or with & |
+' array declarations replace Dim x(100) with Global x[100+1]
+' graphics commands Line,Rect,Oval,Text -> DrawLine,DrawRect,DrawOval,DrawText
+' implement old style Type handling for Each First Last Before After Insert
+' Str becomes String
+' Delete Each list -> list.Clear()
+' Delete -> Release
+' Data->DefData Read->ReadData
+' KeyDown->VKeyDown KeyHit->VKeyHit
+' native Color and ClsColor commands added to header
+
+' not supported / stubbed out
+
+' no float->boolean so error is "bitwise operators can only be used with integers"
+' MouseZSpeed(), FreeBank(bank), Locate( x,y )
+' LoopSound(sound), ChannelPitch(channel,hz),PlayCDTrack( track,mode=0 )
+
+Import brl.retro
+
+Const TAB$=Chr(9)
+
+Global TypePrefix$="bb"
+
+Function main()
+       Local AppArgs$[]=["bb2bmx","bob.bb"]
+       Local srcfile$,destfile$
+       Local n=Len AppArgs
+       If n<2
+               Print "bb2bmx srcfile.bb [destfile.bmx]"
+               End
+       EndIf
+       srcfile$=AppArgs[1]
+       destfile$=Replace$(srcfile,".bb",".bmx")
+       If n>2 destfile$=AppArgs[2]
+       bb2bmx(srcfile,destfile)
+End Function
+
+Function ConvertBB(args$[])
+       Local srcfile$,destfile$
+       If Len args<1 Throw "convertbb option requires a filename"
+       srcfile$=args[0]
+       If Len args>1 destfile=args[1]
+       bb2bmx srcfile,destfile
+End Function
+
+Global Includes:TList
+Global Complete:TList
+Global TypeLists:TList
+
+Function bb2bmx(srcfile$,destfile$)
+       Local   s$,currdir$,inc$,done$
+       Local   destinclude$
+       Local   src:TList,isrc:TList
+       Local   dest:TList,idest:TList
+       Local   incs:TList
+
+       Includes=New TList
+       TypeLists=New TList
+       Complete=New TList
+       
+       currdir=CurrentDir()
+               
+       src=ReadTextFile(srcfile)
+       If Not src Throw "bb2bmx failed to open "+srcfile
+
+       If Not destfile destfile$=Replace$(srcfile,".bb",".bmx")
+       ChangeDir ExtractDir(srcfile)
+
+       WriteVKeyFile
+       WriteBBTypeFile
+       
+       dest=New TList  
+
+       Print "converting "+srcfile
+       ConvertSourceList(src,dest)
+
+' process includes
+
+       While Not Includes.IsEmpty()
+               incs=Includes
+               Includes=New TList
+               For srcfile=EachIn incs
+
+' check if include already converted
+
+                       For done=EachIn complete
+                               If done=srcfile Exit
+                       Next
+                       If done=srcfile Continue
+
+                       complete.AddLast srcfile                        
+                       isrc=ReadTextFile(srcfile)
+                       If Not isrc Throw "bb2bmx failed to open included file "+srcfile
+                       ChangeDir ExtractDir(srcfile)
+
+                       idest=New TList
+                       Print "converting "+srcfile
+
+                       ConvertSourceList(isrc,idest)
+                       destinclude$=Replace$(srcfile,".bb",".bmx")
+                       WriteTextFile(destinclude,idest)
+               Next
+       Wend
+       
+       ChangeDir(currdir)
+
+       For s$=EachIn TypeLists
+               dest.addfirst s$
+       Next
+               
+       dest.addfirst ""
+       dest.addfirst "Import "+Chr(34)+"bbvkey.bmx"+Chr(34)
+       dest.addfirst "Import "+Chr(34)+"bbtype.bmx"+Chr(34)
+
+       WriteTextFile(destfile,dest)
+       
+End Function
+
+Function ProcessInclude$(s$)
+       Local   path$,inc$
+       Local   q,r
+       
+       q=Instr(s,Chr(34))
+       If q=0 Return s$        
+       r=Instr(s,Chr(34),q+1)
+       If r=0 Return s$
+       path$=s[q..r-1]
+
+       path=RealPath(path$)
+       For inc=EachIn Includes
+               If inc=path Exit
+       Next
+       If inc<>path
+               Includes.AddLast(path)  
+       EndIf
+
+       Return Replace$(s$,".bb",".bmx")
+End Function
+
+Function FindToken(s$,t$,p)
+       Local   l$,c
+       t=Lower(t)
+       l=Lower(s)
+       Repeat
+               p=Instr(l,t,p+1)
+               If Not p Exit
+               If p>1
+                       c=l[p-2]
+                       If c>47 And c<58 Continue       '0-9
+                       If c>95 And c<122 Continue      'a-z
+                       If c=Asc("_") Continue
+               EndIf
+               If p+Len(t)-1<Len(l)
+                       c=l[p+Len(t)-1]
+                       If c>47 And c<58 Continue       '0-9
+                       If c>95 And c<122 Continue      'a-z
+                       If c=Asc("_") Continue
+               EndIf
+               Return p
+       Forever
+End Function
+
+Function ReplaceToken$(s$,t$,r$)
+       Local   l$,p,c
+       Repeat
+               p=FindToken(s,t,p)
+               If Not p Exit
+               s=s[..p-1]+r$+s[p+Len(t)-1..]   
+               p:+Len r$
+       Forever
+       Return s
+End Function
+
+Function FindEOC(s$,p) 'return position of next space or command separator
+       Local   q,r
+       q=Instr(s," ",p)
+       If q=0 q=Len s+1
+       r=Instr(s,";",p)
+       If r And r<q q=r
+       r=Instr(s,"<",p)
+       If r And r<q q=r
+       r=Instr(s,">",p)
+       If r And r<q q=r
+       r=Instr(s,"=",p)
+       If r And r<q q=r
+       r=Instr(s,"-",p)
+       If r And r<q q=r
+       r=Instr(s,"+",p)
+       If r And r<q q=r
+       r=Instr(s,"*",p)
+       If r And r<q q=r
+       Return q
+End Function
+
+Function StripDims$(s$)        'remove dimensions in blitz arrays for blitzmax function parameters
+       Local   p,q
+       p=1
+       Repeat
+               p=Instr(s$,"[",p)
+               If p=0 Exit
+               q=Instr(s$,"]",p)
+               If q=0 Exit
+               s$=s$[..p]+s$[q-1..]
+               p=p+1   
+       Forever
+       Return s
+End Function
+
+Function IncrementArrays$(s$)  'replace all arguments inside [] with 
+       Local p,q,a$
+       p=Instr(s$,"[")
+       If p=0 Return
+       p=Instr(s$,"=")
+       If p 
+'              print "IncrementArray rejecting s$="+s$
+               Return s$
+       EndIf
+       p=0
+       While True
+               p=Instr(s$,"[",p)
+               If p=0 Exit
+               q=Instr(s$,"]",p)
+               If q=0 Exit
+               a$=s$[p..q-1]
+               a$=Replace(a$,",","+1,")
+               a$=a$+"+1"
+               s$=s$[..p]+a$+s$[q-1..]
+               p=p+Len(a$)+1
+       Wend
+       Return s$
+End Function
+
+Function ConvertBoolOps$(s$) ' if AND OR not followed by < > = convert to bool operator & | 
+       Local   p,q,r,t 
+
+       While True
+               t=FindToken(s$,"And",p)
+               If t=0 Exit             
+               q=Len(s$)
+               r=FindToken(s$,"Then",t)
+               If r And r<q q=r
+               r=Instr(s$,";",t)
+               If r And r<q q=r
+' q is end of check    
+               r=Instr(s$,"=",t);If r And r<=q p=q;Continue    
+               r=Instr(s$,"<",t);If r And r<=q p=q;Continue    
+               r=Instr(s$,">",t);If r And r<=q p=q;Continue    
+               s$=s[..t-1]+"&"+s[t+2..]
+       Wend
+       p=0
+       While True
+               t=FindToken(s$,"Or",p)
+               If t=0 Exit             
+               q=Len(s$)
+               r=FindToken(s$,"Then",t)
+               If r And r<q q=r
+               r=Instr(s$,";",t)
+               If r And r<q q=r
+' q is end of check    
+               r=Instr(s$,"=",t);If r And r<=q p=q;Continue    
+               r=Instr(s$,"<",t);If r And r<=q p=q;Continue    
+               r=Instr(s$,">",t);If r And r<=q p=q;Continue    
+               s$=s[..t-1]+"|"+s[t+1..]
+       Wend
+       Return s$
+End Function
+
+Function Convert$(s$)  'substring of source line before rem and between any string literals
+       Local   p,q,r,c,n$
+' replace : command separator
+       s$=Replace(s$,":",";")
+'.label->#label        
+       p=Instr(Trim(s),".")
+       If p=1 
+               p=Instr(s,".")
+               s="#"+s[p..]
+       EndIf
+' replace . type specifier
+       p=1
+       Repeat
+               p=Instr(s,".",p+1)
+               If Not p Exit
+               c=s[p]
+               If c>47 And c<58 Continue       'ignore if decimal point
+               s=s[..p-1]+":"+TypePrefix$+s[p..]       
+       Forever
+' replace \ field separator
+       s$=Replace(s$,"\",".")
+' update BASIC API name changes
+       s$=ReplaceToken(s,"freesound","Release")
+       s$=ReplaceToken(s,"channelpan","SetChannelPan")
+       s$=ReplaceToken(s,"filepos","StreamPos")
+       s$=ReplaceToken(s,"seekfile","SeekStream")
+       s$=ReplaceToken(s,"channelvolume","SetChannelVolume")
+       s$=ReplaceToken(s,"readbytes","ReadBank")
+       s$=ReplaceToken(s,"writebytes","WriteBank")
+       s$=ReplaceToken(s,"mousewait","WaitMouse")
+' hidepointer -> hidemouse showpointer -> showmouse
+       s$=ReplaceToken(s,"hidepointer","HideMouse")
+       s$=ReplaceToken(s,"showpointer","ShowMouse")
+' replace boolean operators
+       s$=ReplaceToken(s,"xor","~~")
+       s$=ReplaceToken(s,"stop","DebugStop")
+
+Rem
+       s$=ReplaceToken(s,"and","&")
+       s$=ReplaceToken(s,"or","|")
+       s$=ReplaceToken(s,"chr$","chr")
+
+       s$=ReplaceToken(s,"line","DrawLine")
+       s$=ReplaceToken(s,"rect","DrawRect")
+       s$=ReplaceToken(s,"oval","DrawOval")
+       s$=ReplaceToken(s,"text","DrawText")
+       s$=ReplaceToken(s,"color","SetColor")
+       s$=ReplaceToken(s,"clscolor","SetCLSColor")
+EndRem
+       s$=ReplaceToken(s,"str","String")
+       s$=ReplaceToken(s,"read","ReadData")
+       s$=ReplaceToken(s,"data","DefData")
+       s$=ReplaceToken(s,"restore","RestoreData")
+       s$=ReplaceToken(s,"keydown","VKeyDown")
+       s$=ReplaceToken(s,"keyhit","VKeyHit")
+       s$=ReplaceToken(s,"getkey","WaitKey")
+       s$=ReplaceToken(s,"readpixel","dev.blitz3d.ReadPixel")  'ReadPixelBuffer")
+       s$=ReplaceToken(s,"writepixel","dev.blitz3d.WritePixel")
+       s$=ReplaceToken(s,"graphicswidth","dev.blitz3d.GraphicsWidth")
+       s$=ReplaceToken(s,"graphicsheight","dev.blitz3d.GraphicsHeight")
+
+       s$=ReplaceToken(s,"min","fmin")
+       s$=ReplaceToken(s,"max","fmax")
+
+' delete obj -> obj.remove
+       p=0
+       Repeat
+               p=FindToken(s,"delete",p)
+               If Not p Exit
+               If Lower(s[p+5..p+10])=" each" s=s[..p+5]+"Each "+TypePrefix$+Trim(s[p+10]);Continue            
+               If Lower(s[p+5..p+11])=" first" s=s[..p+5]+"First "+TypePrefix$+Trim(s[p+11]);Continue          
+               If Lower(s[p+5..p+10])=" last" s=s[..p+5]+"Last "+TypePrefix$+Trim(s[p+10]);Continue            
+               q=Instr(s," ",p+7)
+               If q=0 q=Len s+1
+               r=Instr(s,";",p+7)
+               If r And r<q q=r        
+               s=s[..p-1]+s[p+6..q-1]+".Remove()"+s[q-1..]             'p+6
+               p=q
+       Forever
+
+       s$=ConvertBoolOps(s)
+
+       s$=ReplaceToken(s,"delete","Release")
+
+' handle(obj) -> HandleFromObject(obj) object.blah(handle) -> HandleToObject(handle)
+
+       s$=ReplaceToken(s,"handle","HandleFromObject")
+       p=0
+       Repeat
+               p=FindToken(s,"object",p)
+               If p=0 Exit
+               q=Instr(s,":",p)
+               If q=0 Exit
+               r=Instr(s,"(",q)
+               If r=0 Exit
+               n$=s[q..r-1]
+               c=1
+               q=r
+               While c
+                       If r>Len(s) Exit
+                       If s[r]="(" c:+1
+                       If s[r]=")" c:-1
+                       r:+1
+               Wend
+               s=s[..p-1]+n$+"(HandleToObject"+s[q-1..r-1]+")"+s[r..]
+               p=p+Len(n)+16
+       Forever
+
+' replace New Type with New prefix_type 
+       p=0
+       Repeat
+               p=FindToken(s,"New",p)
+               If Not p Exit
+               s=s[..p+3]+TypePrefix$+s[p+3..]
+               p=p+1
+       Forever
+' replace Dim var(size) with Global var[size] 
+       p=0
+       Repeat
+               p=FindToken(s,"Dim",p)
+               If Not p Exit
+               s=s[..p-1]+"Global"+s[p+2..]
+               Repeat
+                       p=Instr(s,"(",p)
+                       If Not p Exit
+                       s=s[..p-1]+"["+s[p..]
+                       p=Instr(s,")",p)
+                       If Not p Exit
+                       s=s[..p-1]+"]"+s[p..]   'was +1
+               Forever
+               s=IncrementArrays(s$)
+               Exit    'no multiple dim calls pre
+'              if not p exit
+       Forever
+' replace function(param[4]) with function(param[])
+       p=0
+       Repeat
+               p=FindToken(s,"Function",p)
+               If Not p Exit
+               p=Instr(s,"(",p)
+               If Not p Exit
+               q=Instr(s,")",p)
+               If Not q Exit
+               n$=StripDims(s[p..q-1])
+               s=s[..p]+n+s[q-1..]             
+               Exit    
+       Forever 
+' for b=each bob -> for b=eachin bob.list
+       p=0
+       Repeat
+               p=FindToken(s,"Each",p)
+               If Not p Exit
+               q=FindEOC(s,p+6)
+               s=s[..p-1]+"EachIn "+Trim(s[p+4..q-1])+"_list"+s[q-1..]         
+               p=q
+       Forever
+' First class
+       p=0
+       Repeat
+               p=FindToken(s,"First",p)
+               If Not p Exit
+               q=FindEOC(s,p+7)
+               n$=Trim(s[p+5..q-1])
+               s=s[..p-1]+TypePrefix+n+"("+n+"_list.First())"+s[q-1..]         
+               p=q+Len(n)*2+14
+       Forever
+' Last class
+       p=0
+       Repeat
+               p=FindToken(s,"Last",p)
+               If Not p Exit
+               q=FindEOC(s,p+6)
+               n$=Trim(s[p+4..q-1])
+               s=s[..p-1]+TypePrefix+n+"("+n+"_list.Last())"+s[q-1..]          
+               p=q+Len(n)*2+13
+       Forever 
+' Insert b Before|After bob -> b.InsertAfter(bob)
+       p=0
+       Repeat
+               p=FindToken(s,"Insert",p)
+               If Not p Exit
+               q=Instr(s," ",p+7)
+               If Not q Exit
+               n$=Lower(s[q..])
+               If n$[..6]="before"
+                       n$="Before"
+                       r=q+7
+               ElseIf n$[..5]="after"
+                       n$="After"
+                       r=q+6
+               Else
+                       Exit
+               EndIf
+               c=FindEOC(s,r+1)
+               s=s[..p-1]+s[p+6..q-1]+".Insert"+n$+"("+s[r..c-1]+")"+s[c..]    'n$+ simon was here
+               p=c
+       Forever
+' After b -> b.After()         
+       p=0
+       Repeat
+               p=FindToken(s,"After",p)
+               If Not p Exit
+               q=Instr(s," ",p+7)
+               If q=0 q=Len s+1
+               r=Instr(s,";",p+7)
+               If r And r<q q=r
+               s=s[..p-1]+s[p+5..q-1]+".After()"+s[q-1..]              
+               p=q
+       Forever
+' Before b -> b.Before()       
+       p=0
+       Repeat
+               p=FindToken(s,"Before",p)
+               If Not p Exit
+               q=Instr(s," ",p+8)
+               If q=0 q=Len s+1
+               r=Instr(s,";",p+8)
+               If r And r<q q=r
+               s=s[..p-1]+s[p+6..q-1]+".Before()"+s[q-1..]             
+               p=q
+       Forever
+       Return s
+End Function
+
+Function FixQuotes$(q$)
+       Local   p,n
+       Repeat
+               p=Instr(q,Chr(34),p)
+               If p=0 Exit
+               p=p+1
+               n=n+1
+       Forever
+       If n&1 Return q$+Chr(34)        'add one for odd quoted lines
+       Return q
+End Function
+
+Function ConvertSourceList(src:TList,dest:TList)
+       Local   in$,out$,l$,p,q,r,inrem,name$
+       Local   strings[]
+       
+       For in=EachIn src
+               l$=Lower$(in)
+               If l$="rem" l$="rem "
+               If inrem
+' terminate remarks            
+                       out$=in$
+                       p=Instr(l$,"endrem")
+                       If p<>1 p=Instr(l$,"end rem")
+                       If p=1
+                               inrem=0
+                       EndIf
+               Else
+' parse strings and remarks
+                       out$=""
+                       in$=fixquotes(in$)
+                       While in$
+                               q=Instr(in$,Chr(34))
+                               r=Instr(in$,";")
+                               inrem=Instr(l$,"rem ")          
+                               If inrem And inrem<q q=0
+                               If r And r<q q=0
+                               If q
+                                       r=Instr(in$,Chr(34),q+1)
+                                       If r=0 r=Len(in$)
+                                       out$=out$+Convert(in$[..q-1])+in$[q-1..r]
+                                       in$=in$[r..]    
+                                       Continue                                
+                               EndIf
+                               If inrem And inrem<r r=0
+                               If r
+                                       out$=out$+Convert(in$[..r-1])+"'"+in$[r..]
+                                       Exit
+                               EndIf
+                               If inrem
+                                       out$=out$+Convert(in$[..inrem-1])+in$[inrem-1..]
+                                       Exit
+                               EndIf
+                               out$=out$+Convert(in$)
+                               Exit
+                       Wend
+               EndIf
+       
+               l$=Lower(out)
+                       
+' type handling extras         
+               If l$[..5]="type "
+                       name$=out$[5..]
+                       p=Instr(name," ")
+                       q=Instr(name,";")
+                       If (Not p) p=Len name
+                       If q And q<p p=q
+                       If p name=name[..p]
+                       name=Trim(name)
+                       p=p+5           
+                       
+                       TypeLists.AddLast "Global "+name+"_list:TList=new TList"
+                       dest.AddLast "Type "+TypePrefix$+name+" Extends TBBType"+out$[p..]
+                       dest.AddLast ""
+                       dest.AddLast TAB$+"Method New()"
+                       dest.AddLast TAB$+TAB$+"Add("+name+"_list)"
+                       dest.AddLast TAB$+"End Method"
+                       dest.AddLast ""
+                       dest.AddLast TAB$+"Method After:"+TypePrefix$+name+"()"
+                       dest.AddLast TAB$+TAB$+"Local t:TLink"
+                       dest.AddLast TAB$+TAB$+"t=_link.NextLink()"
+                       dest.AddLast TAB$+TAB$+"If t Return "+TypePrefix$+name+"(t.Value())"
+                       dest.AddLast TAB$+"End Method"
+                       dest.AddLast ""
+                       dest.AddLast TAB$+"Method Before:"+TypePrefix$+name+"()"
+                       dest.AddLast TAB$+TAB$+"Local t:TLink"
+                       dest.AddLast TAB$+TAB$+"t=_link.PrevLink()"
+                       dest.AddLast TAB$+TAB$+"If t Return "+TypePrefix$+name+"(t.Value())"
+                       dest.AddLast TAB$+"End Method"
+                       dest.AddLast ""
+                       Continue
+               EndIf
+
+' Include "blah.bb" -> Include "blah.bmx"
+               
+               If l$[..8]="include " Or l$[..8]="include"+Chr$(34)
+                       out=ProcessInclude(out)
+               EndIf
+               
+               dest.AddLast out
+               
+       Next
+End Function
+
+Function ReadTextFile:TList(file$)
+       Local   f:TStream,n
+       Local   txt:TList
+       txt=New TList
+       f=ReadStream(file)
+       If Not f Return Null
+       While Not Eof(f)
+               txt.AddLast ReadLine(f)
+               n:+1
+       Wend
+       Return txt
+End Function
+
+Function WriteTextFile(file$,txt:TList)
+       Local   f:TStream,l$
+       f=WriteStream(file)
+       If Not f Return
+       For l$=EachIn txt
+               WriteLine f,l
+       Next
+       CloseStream f
+End Function
+
+Function WriteVKeyFile()
+       Local dest:TStream=WriteFile("bbvkey.bmx")
+       If Not dest Return
+       WriteLine dest,"' virtual key support for legacy Blitz apps"
+       WriteLine dest,""
+       WriteLine dest,"Global VKEY[]=[.."
+       WriteLine dest,"0,KEY_ESCAPE,KEY_1,KEY_2,KEY_3,KEY_4,KEY_5,KEY_6,KEY_7,KEY_8,KEY_9,KEY_0,.."
+       WriteLine dest,"KEY_MINUS,KEY_EQUALS,KEY_BACKSPACE,KEY_TAB,KEY_Q,KEY_W,KEY_E,KEY_R,KEY_T,.."
+       WriteLine dest,"KEY_Y,KEY_U,KEY_I,KEY_O,KEY_P,KEY_OPENBRACKET,KEY_CLOSEBRACKET,KEY_RETURN,.."
+       WriteLine dest,"KEY_LCONTROL,KEY_A,KEY_S,KEY_D,KEY_F,KEY_G,KEY_H,KEY_J,KEY_K,KEY_L,.."
+       WriteLine dest,"KEY_SEMICOLON,KEY_QUOTES,KEY_TILDE,KEY_LSHIFT,KEY_BACKSLASH,.."
+       WriteLine dest,"KEY_Z,KEY_X,KEY_C,KEY_V,KEY_B,KEY_N,KEY_M,KEY_COMMA,KEY_PERIOD,KEY_SLASH,.."
+       WriteLine dest,"KEY_RSHIFT,KEY_NUMMULTIPLY,KEY_ALT,KEY_SPACE,KEY_CAPSLOCK,.."
+       WriteLine dest,"KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5,KEY_F6,KEY_F7,KEY_F8,KEY_F9,KEY_F10,.."
+       WriteLine dest,"KEY_NUMLOCK,KEY_SCROLL,KEY_NUM7,KEY_NUM8,KEY_NUM9,KEY_NUMSUBTRACT,KEY_NUM4,.."
+       WriteLine dest,"KEY_NUM5,KEY_NUM6,KEY_NUMADD,KEY_NUM1,KEY_NUM2,KEY_NUM3,KEY_NUM0,.."
+       WriteLine dest,"KEY_NUMDECIMAL,KEY_NUMSLASH,KEY_F11,KEY_F12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,.."
+       WriteLine dest,"0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,.."
+       WriteLine dest,"KEY_EQUALS,0,0,KEY_MEDIA_PREV_TRACK,0,0,0,0,0,0,0,0,KEY_MEDIA_NEXT_TRACK,0,0,.."
+       WriteLine dest,"KEY_ENTER,KEY_RCONTROL,0,0,KEY_VOLUME_MUTE,0,KEY_MEDIA_PLAY_PAUSE,0,.."
+       WriteLine dest,"KEY_MEDIA_STOP,0,0,0,0,0,0,0,0,0,KEY_VOLUME_DOWN,0,KEY_VOLUME_UP,0,.."
+       WriteLine dest,"KEY_BROWSER_HOME,KEY_DECIMAL,0,KEY_NUMDIVIDE,0,KEY_SCREEN,.."
+       WriteLine dest,"0,0,0,0,0,0,0,0,0,0,0,0,0,KEY_PAUSE,0,KEY_HOME,KEY_UP,KEY_PAGEUP,0,.."
+       WriteLine dest,"KEY_LEFT,0,KEY_RIGHT,0,KEY_END,KEY_DOWN,KEY_PAGEDOWN,KEY_INSERT,KEY_DELETE,.."
+       WriteLine dest,"0,0,0,0,0,0,0,KEY_LWIN,KEY_RWIN,0,0,0,0,0,0,0,0,KEY_BROWSER_SEARCH,.."
+       WriteLine dest,"KEY_BROWSER_FAVORITES,KEY_BROWSER_REFRESH,KEY_BROWSER_STOP,KEY_BROWSER_FORWARD,.."
+       WriteLine dest,"KEY_BROWSER_BACK,0,KEY_LAUNCH_MAIL,KEY_LAUNCH_MEDIA_SELECT]"
+       WriteLine dest,""       
+       WriteLine dest,"Function VKeyDown(key);return KeyDown(VKEY[key]);End Function"
+       WriteLine dest,"Function VKeyHit(key);return KeyHit(VKEY[key]);End Function"
+       WriteLine dest,""
+       WriteLine dest,"'currently unsupported in BlitzMax"     
+       WriteLine dest,""
+       WriteLine dest,"Function Locate( x,y );return 0;End Function"
+       WriteLine dest,"Function MouseZSpeed();return 0;End Function"
+       WriteLine dest,"Function FreeBank(bank);return 0;End Function"
+       WriteLine dest,"Function LoopSound(sound);return 0;End Function"
+       WriteLine dest,"Function ChannelPitch(channel,hz);return 0;End Function"
+       WriteLine dest,"Function PlayCDTrack( track,mode=0 );return 0;End Function"
+       WriteLine dest,"Function SoundVolume( sound,volume# );return 0;End Function"
+       WriteLine dest,""
+       CloseFile dest
+End Function
+       
+Function WriteBBTypeFile()
+       Local dest:TStream=WriteFile("bbtype.bmx")
+       If Not dest Return
+       WriteLine dest,"' BBType adds legacy Type functionality to BlitzMax Type"
+       WriteLine dest,""
+       WriteLine dest,"Type TBBType"
+       WriteLine dest,""
+       WriteLine dest,"        Field _list:TList"
+       WriteLine dest,"        Field _link:TLink"
+       WriteLine dest,""
+       WriteLine dest,"        Method Add(t:TList)"
+       WriteLine dest,"                _list=t"
+       WriteLine dest,"                _link=_list.AddLast(self)"
+       WriteLine dest,"        End Method"
+       WriteLine dest,""
+       WriteLine dest,"        Method InsertBefore(t:TBBType)"
+       WriteLine dest,"                _link.Remove"
+       WriteLine dest,"                _link=_list.InsertBeforeLink(self,t._link)"
+       WriteLine dest,"        End Method"
+       WriteLine dest,""
+       WriteLine dest,"        Method InsertAfter(t:TBBType)"
+       WriteLine dest,"                _link.Remove"
+       WriteLine dest,"                _link=_list.InsertAfterLink(self,t._link)"
+       WriteLine dest,"        End Method"
+       WriteLine dest,""
+       WriteLine dest,"        Method Remove()"
+       WriteLine dest,"                _list.remove self"
+       WriteLine dest,"        End Method"
+       WriteLine dest,""
+       WriteLine dest,"End Type"
+       WriteLine dest,""
+       WriteLine dest,"Function DeleteLast(t:TBBType)"
+       WriteLine dest,"        if t TBBType(t._list.Last()).Remove()"
+       WriteLine dest,"End Function"
+       WriteLine dest,""
+       WriteLine dest,"Function DeleteFirst(t:TBBType)"
+       WriteLine dest,"        if t TBBType(t._list.First()).Remove()"
+       WriteLine dest,"End Function"
+       WriteLine dest,""
+       WriteLine dest,"Function DeleteEach(t:TBBType)"
+       WriteLine dest,"        if t t._list.Clear()"
+       WriteLine dest,"End Function"
+       WriteLine dest,""
+       WriteLine dest,"Function ReadString$(in:TStream)"
+       WriteLine dest,"        local   length"
+       WriteLine dest,"        length=readint(in)"
+       WriteLine dest,"        if length>0 and length<1024*1024 return brl.stream.readstring(in,length)"
+       WriteLine dest,"End Function"
+       WriteLine dest,""
+       WriteLine dest,"Function HandleToObject:Object(obj:Object)"
+       WriteLine dest,"        Return obj"
+       WriteLine dest,"End Function"
+       WriteLine dest,""
+       WriteLine dest,"Function HandleFromObject(obj:Object)"
+       WriteLine dest,"        Local h=HandleToObject(obj)"
+       WriteLine dest,"        Return h"
+       WriteLine dest,"End Function"
+       WriteLine dest,""
+       WriteLine dest,""
+       CloseFile dest
+End Function
diff --git a/src/bmk/bmk_config.bmx b/src/bmk/bmk_config.bmx
new file mode 100644 (file)
index 0000000..8801f0e
--- /dev/null
@@ -0,0 +1,159 @@
+
+Strict
+
+Import BRL.MaxUtil
+
+Import Pub.MacOS
+
+Const ALL_SRC_EXTS$="bmx;i;c;m;cpp;cxx;cc;mm;h;hpp;hxx;hh;s;asm"
+
+Global opt_arch$
+Global opt_server$
+Global opt_outfile$
+Global opt_framework$
+Global opt_apptype$="console"
+Global opt_debug=False
+Global opt_threaded=False
+Global opt_release=False
+Global opt_configmung$=""
+Global opt_kill=False
+Global opt_username$="nobody"
+Global opt_password$="anonymous"
+Global opt_modfilter$="."
+Global opt_all=False
+Global opt_quiet=False
+Global opt_verbose=False
+Global opt_execute=False
+Global opt_proxy$
+Global opt_proxyport
+Global opt_traceheaders
+Global opt_appstub$="brl.appstub" ' BaH 28/9/2007
+
+Global opt_dumpbuild
+
+Global cfg_platform$
+
+?MacOS
+
+cfg_platform="macos"
+Global macos_version
+Gestalt Asc("s")Shl 24|Asc("y")Shl 16|Asc("s")Shl 8|Asc("v"),macos_version
+
+?MacOsPPC
+If is_pid_native(0) opt_arch="ppc" Else opt_arch="x86"
+
+?MacOsX86
+If is_pid_native(0) opt_arch="x86" Else opt_arch="ppc"
+
+?Win32
+
+opt_arch="x86"
+cfg_platform="win32"
+
+'Fudge PATH so exec sees our MinGW first!
+Local mingw$=getenv_( "MINGW" )
+If mingw
+       Local path$=getenv_( "PATH" )
+       If path
+               path=mingw+"\bin;"+path
+               putenv_ "PATH="+path
+       EndIf
+EndIf
+
+?Linux
+
+opt_arch="x86"
+cfg_platform="linux"
+
+?
+
+ChangeDir LaunchDir
+
+Function CmdError()
+       Throw "Command line error"
+End Function
+
+Function ParseConfigArgs$[]( args$[] )
+
+       Local n
+       
+       If getenv_( "BMKDUMPBUILD" )
+               opt_dumpbuild=1
+               opt_quiet=True
+       EndIf
+       
+       For n=0 Until args.length
+               Local arg$=args[n]
+               If arg[..1]<>"-" Exit
+               Select arg[1..]
+               Case "a"
+                       opt_all=True
+               Case "q"
+                       opt_quiet=True
+               Case "v"
+                       opt_verbose=True
+               Case "x"
+                       opt_execute=True
+               Case "d"
+                       opt_debug=True
+                       opt_release=False
+               Case "r"
+                       opt_debug=False
+                       opt_release=True
+               Case "h"
+                       opt_threaded=True
+               Case "k"
+                       opt_kill=True
+               Case "z"
+                       opt_traceheaders=True
+               Case "y"
+                       n:+1
+                       If n=args.length CmdError
+                       opt_proxy=args[n]
+                       Local i=opt_proxy.Find(":")
+                       If i<>-1
+                               opt_proxyport=Int( opt_proxy[i+1..] )
+                               opt_proxy=opt_proxy[..i]
+                       EndIf
+               Case "g"
+                       n:+1
+                       If n=args.length CmdError
+                       opt_arch=args[n].ToLower()
+               Case "t"
+                       n:+1
+                       If n=args.length CmdError
+                       opt_apptype=args[n].ToLower()
+               Case "o"
+                       n:+1
+                       If n=args.length CmdError
+                       opt_outfile=args[n]
+               Case "f"
+                       n:+1
+                       If n=args.length CmdError
+                       opt_framework=args[n]
+               Case "s"
+                       n:+1
+                       If n=args.length CmdError
+                       opt_server=args[n]
+               Case "u"
+                       n:+1
+                       If n=args.length CmdError
+                       opt_username=args[n]
+               Case "p"
+                       n:+1
+                       If n=args.length CmdError
+                       opt_password=args[n]
+               Case "b"
+                       n:+1
+                       If n=args.length CmdError
+                       opt_appstub=args[n]
+               Default
+                       CmdError
+               End Select
+       Next
+       
+       Return args[n..]
+
+End Function
+
+
diff --git a/src/bmk/bmk_make.bmx b/src/bmk/bmk_make.bmx
new file mode 100644 (file)
index 0000000..f6a253c
--- /dev/null
@@ -0,0 +1,395 @@
+
+Strict
+
+Import "bmk_modutil.bmx"
+
+Rem
+Experimental speedup hack by Mark!
+
+Should allow you to modify non-interface affecting code without triggering lots of recompiles.
+
+Works by determining whether blah.bmx's .i file physically changes after blah.bmx is compiled.
+
+If not, then anything importing blah.bmx may not need to be recompiled.
+
+Uses a new '.i2' file which is updated only when actual .i file content changes.
+End Rem
+Global EXPERIMENTAL_SPEEDUP
+
+Local t$=getenv_( "BMK_SPEEDUP" )
+If t EXPERIMENTAL_SPEEDUP=True
+
+Type TFile
+
+       Field path$,time
+
+       Function Create:TFile( path$,files:TList )
+               Local f:TFile=New TFile
+               f.path=path
+               f.time=FileTime(path)
+               If files files.AddFirst f
+               Return f
+       End Function
+
+End Type
+
+Global cc_opts$
+Global bcc_opts$
+Global app_main$
+Global app_type$
+Global src_files:TList
+Global obj_files:TList
+Global lnk_files:TList
+Global tmp_stack:TList
+Global ext_files:TList
+
+Function Push( o:Object )
+       tmp_stack.AddLast o
+End Function
+
+Function Pop:Object() 
+       Return tmp_stack.RemoveLast()
+End Function
+
+Function FindFile:TFile( path$,files:TList )
+       path=path.ToLower()
+       Local f:TFile
+       For f=EachIn files
+               If f.path.ToLower()=path Return f
+       Next
+End Function
+
+Function MaxTime( files:TList )
+       Local f:TFile,t
+       For f=EachIn files
+               If f.time>t t=f.time
+       Next
+       Return t
+End Function
+
+Function FilePaths:TList( files:TList )
+       Local f:TFile,p:TList=New TList
+       For f=EachIn files
+               p.AddLast f.path
+       Next
+       Return p
+End Function
+
+Function AddList( src:TList,dst:TList )
+       Local t:Object
+       For t=EachIn src
+               dst.AddLast t
+       Next
+End Function
+
+Function BeginMake()
+       cc_opts=Null
+       bcc_opts=Null
+       app_main=Null
+       src_files=New TList
+       obj_files=New TList
+       lnk_files=New TList
+       tmp_stack=New TList
+       ext_files=New TList
+End Function
+
+'returns mod interface file
+Function MakeMod:TFile( mod_name$ )
+
+       Local path$=ModulePath(mod_name)
+       Local id$=ModuleIdent(mod_name)
+       Local src_path$=path+"/"+id+".bmx"
+       Local arc_path$=path+"/"+id+opt_configmung+".a"
+       Local iface_path$=path+"/"+id+opt_configmung+".i"
+       
+       mod_opts = New TModOpt ' BaH
+       
+       Local iface:TFile=FindFile( iface_path,src_files )
+       If iface Return iface
+
+       Assert Not FindFile( arc_path,lnk_files )
+
+       Local arc:TFile=TFile.Create( arc_path,Null )
+
+       If (mod_name+".").Find(opt_modfilter)=0 And FileType(src_path)=FILETYPE_FILE
+
+               Push cc_opts
+               Push bcc_opts
+               Push obj_files
+
+               cc_opts=""
+               cc_opts:+" -I"+CQuote(path)
+               cc_opts:+" -I"+CQuote(ModulePath(""))
+
+               If opt_release cc_opts:+" -O2 -DNDEBUG"
+               If opt_threaded cc_opts:+" -DTHREADED"
+
+               bcc_opts=" -g "+opt_arch
+               bcc_opts:+" -m "+mod_name$
+
+               If opt_quiet bcc_opts:+" -q"
+               If opt_verbose bcc_opts:+" -v"
+               If opt_release bcc_opts:+" -r"
+               If opt_threaded bcc_opts:+" -h"
+
+               obj_files=New TList
+               
+               MakeSrc src_path,True
+
+               If MaxTime( obj_files )>arc.time Or opt_all
+                       If Not opt_quiet Print "Archiving:"+StripDir(arc_path)
+                       CreateArc arc_path,FilePaths( obj_files )
+                       arc.time=FileTime(arc_path)
+               EndIf
+
+               obj_files=TList(Pop())
+               bcc_opts=String(Pop())
+               cc_opts=String(Pop())
+       EndIf
+
+       Local src:TFile=MakeSrc( iface_path,False )
+
+       lnk_files.AddFirst arc
+
+       Return src
+
+End Function
+
+'adds to obj_files
+'returns input src file
+Function MakeSrc:TFile( src_path$,buildit )
+
+       Local src:TFile=FindFile( src_path,src_files )
+       If src Return src
+
+       If FileType( src_path )<>FILETYPE_FILE Return
+
+       src=TFile.Create( src_path,src_files )
+
+       Local src_file:TSourceFile=ParseSourceFile( src_path )
+       If Not src_file Return
+       
+       Local main_file=(src_path=app_main)
+       
+       Local keep_opts:TModOpt = mod_opts ' BaH
+       
+       If main_file
+               If src_file.framewk
+                       If opt_framework Throw "Framework already specified on commandline"
+                       opt_framework=src_file.framewk
+                       bcc_opts:+" -f "+opt_framework
+                       MakeMod opt_framework
+               Else
+                       If app_type="bmx"
+                               For Local t$=EachIn EnumModules()
+                                       If t.Find("brl.")=0 Or t.Find("pub.")=0
+                                               If t<>"brl.blitz" And t<>opt_appstub MakeMod t
+                                       EndIf
+                               Next
+                       EndIf
+               EndIf
+       Else If src_file.framewk
+               Throw "Framework must appear in main source file"
+       EndIf
+       
+       mod_opts = keep_opts ' BaH
+       
+       push cc_opts
+       Push CurrentDir()
+       
+       ChangeDir ExtractDir( src_path )
+       
+       Local src_ext$=ExtractExt( src_path ).ToLower()
+       
+       If Match( src_ext,"bmx;i" )
+               'incbins
+               For Local inc$=EachIn src_file.incbins
+                       Local time=FileTime( inc )
+                       If time>src.time src.time=time
+               Next
+               'includes
+               For Local inc$=EachIn src_file.includes
+                       Local inc_ext$=ExtractExt(inc).ToLower()
+                       If Match(inc_ext,"bmx")
+                               Local dep:TFile=MakeSrc(RealPath(inc),False)
+                               If Not dep Continue
+                               If dep.time>src.time src.time=dep.time
+                       Else
+                               Throw "Unrecognized Include file type: "+inc
+                       EndIf
+               Next
+
+               'module imports
+               For Local imp$=EachIn src_file.modimports
+                       Local dep:TFile=MakeMod(imp)
+                       If Not dep Continue
+                       cc_opts:+" -I"+CQuote(ExtractDir(dep.path))
+                       If dep.time>src.time src.time=dep.time
+               Next
+
+               mod_opts = keep_opts ' BaH
+
+               For Local imp$=EachIn mod_opts.ld_opts ' BaH
+                       ext_files.AddLast TModOpt.setPath(imp, ExtractDir(src_path))
+               Next
+
+               'quoted imports
+               For Local imp$=EachIn src_file.imports
+                       If imp[0]=Asc("-")
+                               ext_files.AddLast imp
+                               Continue
+                       EndIf
+                       Local imp_ext$=ExtractExt(imp).ToLower()
+                       If Match( imp_ext,"h;hpp;hxx;hh" )
+                               cc_opts:+" -I"+CQuote(RealPath(ExtractDir(imp)))
+                       Else If Match( imp_ext,"o;a;lib" )
+                               ext_files.AddLast RealPath(imp)
+                       Else If Match( imp_ext,ALL_SRC_EXTS )
+
+                               Local dep:TFile=MakeSrc(RealPath(imp),True)
+
+                               If Not dep Or Not Match( imp_ext,"bmx;i" ) Continue
+                               
+                               If EXPERIMENTAL_SPEEDUP And Match( imp_ext,"bmx" )
+                                       Local p$=ExtractDir( dep.path )+"/.bmx"
+                                       Local i_path$=p+"/"+StripDir( dep.path )+opt_configmung+".i2"
+                                       If FileType( i_path )=FILETYPE_FILE
+                                               Local i_time=FileTime( i_path )
+                                               If i_time>src.time src.time=i_time
+                                       Else
+                                               If dep.time>src.time src.time=dep.time
+                                       EndIf
+                               Else
+                                       If dep.time>src.time src.time=dep.time
+                               EndIf
+                               
+                       Else
+                               Throw "Unrecognized Import file type: "+imp
+                       EndIf
+               Next
+       Else If Match( src_ext,"c;m;cpp;cxx;cc;mm;h;hpp;hxx;hh" )
+               For Local inc$=EachIn src_file.includes
+                       Local inc_ext$=ExtractExt(inc).ToLower()
+                       If Not Match(inc_ext,"h;hpp;hxx;hh")
+                               Continue
+                       EndIf
+                       Local path$=RealPath(inc)
+                       Local dep:TFile=MakeSrc(path,False)
+                       If dep And dep.time>src.time src.time=dep.time
+                       If Not opt_traceheaders Continue
+                       Local src$=StripExt(path)+".cpp"
+                       If FileType(src)<>FILETYPE_FILE
+                               src=""
+                       EndIf
+                       If Not src Continue
+                       MakeSrc src,True
+               Next
+       EndIf
+       
+       If buildit And Match( src_ext,"bmx;c;m;cpp;cxx;cc;mm;s;asm" )
+       
+               Local p$=ExtractDir( src_path )+"/.bmx"
+               
+               If opt_dumpbuild Or FileType( p )=FILETYPE_NONE
+                       CreateDir p
+                       'Sys "mkdir "+p   'Windows no likey...
+               EndIf
+               
+               If FileType( p )<>FILETYPE_DIR Throw "Unable to create temporary directory"
+
+               Local obj_path$=p+"/"+StripDir( src_path )
+               If main_file obj_path:+"."+opt_apptype
+               obj_path:+opt_configmung+".o"
+
+               If src.time>FileTime( obj_path ) Or opt_all
+
+                       If Not opt_quiet Print "Compiling:"+StripDir(src_path)
+                       Select src_ext
+                       Case "bmx"
+                               Local opts$=bcc_opts
+                               If main_file opts=" -t "+opt_apptype+opts
+                       
+                               CompileBMX src_path,obj_path,opts
+                                               
+                               If EXPERIMENTAL_SPEEDUP
+                                       Local i_path$=StripExt( obj_path )+".i"
+
+                                       If FileType( i_path )=FILETYPE_FILE
+                               
+                                               Local i_path2$=i_path+"2",update=True
+
+                                               If Not opt_all And FileType( i_path2 )=FILETYPE_FILE And src.time=FileTime( src.path )
+                                                       If FileSize( i_path )=FileSize( i_path2 )
+                                                               Local i_bytes:Byte[]=LoadByteArray( i_path )
+                                                               Local i_bytes2:Byte[]=LoadByteArray( i_path2 )
+                                                               If i_bytes.length=i_bytes2.length And memcmp_( i_bytes,i_bytes2,i_bytes.length )=0
+                                                                       update=False
+                                                               EndIf
+                                                       EndIf
+                                               EndIf
+                                               If update CopyFile i_path,i_path2
+                                       EndIf
+                               EndIf
+
+                       Case "c","m","cpp","cxx","cc","mm"
+                               CompileC src_path,obj_path,cc_opts
+                       Case "s","asm"
+                               Assemble src_path,obj_path
+                       End Select
+               EndIf
+               Local obj:TFile=TFile.Create( obj_path,obj_files )
+               lnk_files.AddFirst obj
+       EndIf
+
+       ChangeDir String(Pop())
+       cc_opts=String(Pop())
+       
+       Return src
+       
+End Function
+
+Function MakeApp:TFile( Main$,makelib )
+
+       app_main=Main
+       
+       cc_opts=""
+       cc_opts:+" -I"+CQuote(ModulePath(""))
+       
+       If opt_release cc_opts:+" -O2 -DNDEBUG"
+       If opt_threaded cc_opts:+" -DTHREADED"
+
+       bcc_opts=" -g "+opt_arch
+
+       If opt_quiet bcc_opts:+" -q"
+       If opt_verbose bcc_opts:+" -v"
+       If opt_release bcc_opts:+" -r"
+       If opt_threaded bcc_opts:+" -h"
+
+       If opt_framework bcc_opts:+" -f "+opt_framework
+       
+       Local app_ext$=ExtractExt( app_main ).ToLower()
+       Select app_ext
+       Case "bmx"
+               app_type="bmx"
+               MakeMod "brl.blitz"
+               MakeSrc Main,True
+               MakeMod opt_appstub
+       Case "c","cpp","cxx","cc","mm"
+               app_type="c/c++"
+               If opt_framework MakeMod opt_framework
+               MakeSrc Main,True
+       Default
+               Throw "Unrecognized app source file extension:"+app_ext
+       End Select
+       
+       If MaxTime( lnk_files )>FileTime( opt_outfile ) Or opt_all
+               If Not opt_quiet Print "Linking:"+StripDir( opt_outfile )
+               lnk_files=FilePaths( lnk_files )
+               AddList ext_files,lnk_files
+               LinkApp opt_outfile,lnk_files,makelib
+       EndIf
+       
+       app_main=""
+
+End Function
+
diff --git a/src/bmk/bmk_modinfo.bmx b/src/bmk/bmk_modinfo.bmx
new file mode 100644 (file)
index 0000000..7f2c99d
--- /dev/null
@@ -0,0 +1,60 @@
+
+Strict
+
+Import "bmk_modutil.bmx"
+Import "bmk_util.bmx"
+
+Type TInfo
+       Field info:TList=New TList
+       
+       Method Find$( key$ )
+               key=key.ToLower()+":"
+               For Local t$=EachIn info
+                       If t.ToLower()[..Len(key)]=key Return t[Len(key)..].Trim()
+               Next
+       End Method
+       
+       Method ReadFromStream:TModInfo( stream:TStream )
+               While Not stream.Eof()
+                       Local t$=stream.ReadLine()
+                       If Not t Return
+                       info.AddLast t
+               Wend
+       End Method
+End Type
+
+Type TModInfo Extends TInfo
+
+       Field name$
+       Field version#
+       Field modprivs$
+       Field modserver$
+       Field serverinfo:Object
+
+       Function CreateFromModule:TModInfo( name$ )
+               Local path$=ModuleInterface( name,"release."+cfg_platform+"."+opt_arch )
+               If FileType(path)<>FILETYPE_FILE Return
+               Local src:TSourceFile=ParseSourceFile( path )
+               If Not src Return
+               Local modinfo:TModInfo=New TModInfo
+               modinfo.name=name
+               modinfo.info=src.info
+               modinfo.info.AddFirst "Module: "+name
+               modinfo.version=Float( modinfo.Find( "Version" ) )
+               modinfo.modserver=modinfo.Find( "ModServer" )
+               Return modinfo
+       End Function
+       
+       Function CreateFromStream:TModInfo( stream:TStream )
+               Local modinfo:TModInfo=New TModInfo
+               modinfo.ReadFromStream stream
+               modinfo.name=modinfo.Find( "Module" )
+               If Not modinfo.name Return
+               modinfo.version=Float( modinfo.Find( "Version" ) )
+               modinfo.modprivs=modinfo.Find( "ModPrivs" )
+               modinfo.modserver=modinfo.Find( "ModServer" )
+               Return modinfo
+       End Function
+
+End Type
+
diff --git a/src/bmk/bmk_modutil.bmx b/src/bmk/bmk_modutil.bmx
new file mode 100644 (file)
index 0000000..aeab773
--- /dev/null
@@ -0,0 +1,187 @@
+
+Strict
+
+Import BRL.MaxUtil
+Import BRL.TextStream
+
+Import "bmk_util.bmx"
+
+Type TSourceFile
+       Field ext$              'one of: "bmx", "i", "c", "cpp", "m", "s", "h"
+       Field path$
+       Field modid$
+       Field framewk$
+       Field info:TList=New TList
+
+       Field modimports:TList=New TList
+       
+       Field imports:TList=New TList
+       Field includes:TList=New TList
+       Field incbins:TList=New TList
+       
+       Field declids:TList=New TList
+End Type
+
+Function CharIsDigit( ch )
+       Return ch>=Asc("0") And ch<=Asc("9")
+End Function
+
+Function CharIsAlpha( ch )
+       Return ch=Asc("_") Or (ch>=Asc("a") And ch<=Asc("z")) Or (ch>=Asc("A") And ch<=Asc("Z"))
+End Function
+
+Function ValidSourceExt( ext$ )
+       Select ext.ToLower()
+       Case "bmx","i"
+       Case "c","m","h"
+       Case "cpp","cxx","mm","hpp","hxx"
+       Case "s","asm"
+       Default
+               Return False
+       End Select
+       Return True
+End Function
+
+Function ParseSourceFile:TSourceFile( path$ )
+
+       If FileType(path)<>FILETYPE_FILE Return
+
+       Local ext$=ExtractExt( path ).ToLower()
+       If Not ValidSourceExt( ext ) Return
+
+       Local file:TSourceFile=New TSourceFile
+       file.ext=ext
+       file.path=path
+       
+       Local str$=LoadText( path )
+
+       Local pos,in_rem,cc=True
+
+       While pos<Len(str)
+
+               Local eol=str.Find( "~n",pos )
+               If eol=-1 eol=Len(str)
+
+               Local line$=str[pos..eol].Trim()
+               pos=eol+1
+
+               Select ext
+               Case "bmx","i"
+
+                       Local n=line.Find( "'" )
+                       If n<>-1 line=line[..n]
+                       
+                       If Not line Continue
+
+                       Local lline$=line.Tolower()
+
+                       If in_rem
+                               If lline[..6]="endrem" Or lline[..7]="end rem" 
+                                       in_rem=False
+                               EndIf
+                               Continue
+                       Else If lline[..3]="rem"
+                               in_rem=True
+                               Continue
+                       EndIf
+
+                       If lline[..1]="?"
+                               Local t$=lline[1..].Trim()
+                               
+                               Local cNot
+                               If t.StartsWith( "not " )
+                                       cNot=True
+                                       t=t[4..].Trim()
+                               EndIf
+
+                               Select t
+                               Case ""
+                                       cc=True
+                               Case "debug"
+                                       cc=opt_debug
+                               Case "threaded"
+                                       cc=opt_threaded
+?x86
+                               Case "x86" cc=opt_arch="x86"
+?ppc
+                               Case "ppc" cc=opt_arch="ppc"
+?
+?Win32
+                               Case "win32" cc=True
+                               Case "win32x86" cc=opt_arch="x86"
+                               Case "win32ppc" cc=opt_arch="ppc"
+?Linux
+                               Case "linux" cc=True
+                               Case "linuxx86" cc=opt_arch="x86"
+                               Case "linuxppc" cc=opt_arch="ppc"
+?MacOS
+                               Case "macos" cc=True
+                               Case "macosx86" cc=opt_arch="x86"
+                               Case "macosppc" cc=opt_arch="ppc"
+?
+                               Default
+                                       cc=False
+                               End Select
+                               If cNot cc=Not cc
+                               Continue
+                       EndIf
+
+                       If Not cc Continue
+
+                       If Not CharIsAlpha( lline[0] ) Continue
+
+                       Local i=1
+                       While i<lline.length And (CharIsAlpha(lline[i]) Or CharIsDigit(lline[i]))
+                               i:+1
+                       Wend
+                       If i=lline.length Continue
+                       
+                       Local key$=lline[..i]
+                       
+                       Local val$=line[i..].Trim(),qval$,qext$
+                       If val.length>1 And val[0]=34 And val[val.length-1]=34
+                               qval=val[1..val.length-1]
+                       EndIf
+
+                       Select key
+                       Case "module"
+                               file.modid=val.ToLower()
+                       Case "framework"
+                               file.framewk=val.ToLower()
+                       Case "import"
+                               If qval
+                                       file.imports.AddLast qval
+                               Else
+                                       file.modimports.AddLast val.ToLower()
+                               EndIf
+                       Case "incbin"
+                               If qval
+                                       file.incbins.AddLast qval
+                               EndIf
+                       Case "include"
+                               If qval
+                                       file.includes.AddLast qval
+                               EndIf
+                       Case "moduleinfo"
+                               If qval
+                                       file.info.AddLast qval
+                                       If mod_opts mod_opts.addOption(qval) ' BaH
+                               EndIf
+                       End Select
+               Case "c","m","h","cpp","cxx","hpp","hxx"
+                       If line[..8]="#include"
+                               Local val$=line[8..].Trim(),qval$,qext$
+                               If val.length>1 And val[0]=34 And val[val.length-1]=34
+                                       qval=val[1..val.length-1]
+                               EndIf
+                               If qval
+                                       file.includes.AddLast qval
+                               EndIf
+                       EndIf
+               End Select
+
+       Wend
+       
+       Return file
+
+End Function
diff --git a/src/bmk/bmk_util.bmx b/src/bmk/bmk_util.bmx
new file mode 100644 (file)
index 0000000..5c122d8
--- /dev/null
@@ -0,0 +1,359 @@
+
+Strict
+
+Import "bmk_config.bmx"
+
+'OS X Nasm doesn't work? Used to produce incorrect reloc offsets - haven't checked for a while 
+Const USE_NASM=False
+
+Const CC_WARNINGS=False'True
+
+Type TModOpt ' BaH
+       Field cc_opts:String = ""
+       Field ld_opts:TList = New TList
+       
+       Method addOption(qval:String)
+               If qval.startswith("CC_OPTS") Then
+                       cc_opts:+ " " + qval[qval.find(":") + 1..].Trim()
+               ElseIf qval.startswith("LD_OPTS") Then
+                       Local opt:String = qval[qval.find(":") + 1..].Trim()
+                       
+                       If opt.startsWith("-L") Then
+                               opt = "-L" + CQuote(opt[2..])
+                       End If
+                       
+                       ld_opts.addLast opt
+               End If
+       End Method
+       
+       Method hasCCopt:Int(value:String)
+               Return cc_opts.find(value) >= 0
+       End Method
+
+       Method hasLDopt:Int(value:String)
+               For Local opt:String = EachIn ld_opts
+                       If opt.find(value) >= 0 Then
+                               Return True
+                       End If
+               Next
+               Return False
+       End Method
+
+       Function setPath:String(value:String, path:String)
+               Return value.Replace("%PWD%", path)
+       End Function
+       
+End Type
+
+Global mod_opts:TModOpt ' BaH
+
+Function Match( ext$,pat$ )
+       Return (";"+pat+";").Find( ";"+ext+";" )<>-1
+End Function
+
+Function HTTPEsc$( t$ )
+       t=t.Replace( " ","%20" )
+       Return t
+End Function
+
+Function Sys( cmd$ )
+       If opt_verbose
+               Print cmd
+       Else If opt_dumpbuild
+               Local p$=cmd
+               p=p.Replace( BlitzMaxPath()+"/","./" )
+               WriteStdout p+"~n"
+               Local t$="mkdir "
+               If cmd.StartsWith( t ) And FileType( cmd[t.length..] ) Return
+       EndIf
+       Return system_( cmd )
+End Function
+
+Function CQuote$( t$ )
+       If t And t[0]=Asc("-") Return t
+       For Local i=0 Until t.length
+               If t[i]=Asc(".") Continue
+               If t[i]=Asc("/") Continue
+?Win32
+               If t[i]=Asc("\") Continue
+?
+               If t[i]=Asc("_") Or t[i]=Asc("-") Continue
+               If t[i]>=Asc("0") And t[i]<=Asc("9") Continue
+               If t[i]>=Asc("A") And t[i]<=Asc("Z") Continue
+               If t[i]>=Asc("a") And t[i]<=Asc("z") Continue
+               Return "~q"+t+"~q"
+       Next
+       Return t
+End Function
+
+Function Ranlib( dir$ )
+       '
+?MacOS
+       If macos_version>=$1040 Return
+?
+       '
+       For Local f$=EachIn LoadDir( dir )
+               Local p$=dir+"/"+f
+               Select FileType( p )
+               Case FILETYPE_DIR
+                       Ranlib p
+               Case FILETYPE_FILE
+                       If ExtractExt(f).ToLower()="a" Sys "ranlib "+p
+               End Select
+       Next
+End Function
+
+Function Assemble( src$,obj$ )
+       DeleteFile obj
+       Local cmd$
+?MacOS
+       If opt_arch="ppc" 
+               cmd="as -arch ppc"
+       Else
+               If USE_NASM
+                       cmd="nasm -f macho"
+               Else
+                       cmd="as -arch i386"
+               EndIf
+       EndIf
+       cmd:+" -W -o "+CQuote(obj)+" "+CQuote(src);
+?Win32
+       cmd$=CQuote(BlitzMaxPath()+"/bin/fasm")+" "+CQuote(src)+" "+CQuote(obj)
+?Linux
+       cmd$=CQuote(BlitzMaxPath()+"/bin/fasm")+" -m32768 "+CQuote(src)+" "+CQuote(obj)
+?
+       If Sys( cmd )
+               Throw "Build Error: Failed to assemble "+src
+       EndIf
+End Function
+
+Function CompileC( src$,obj$,opts$ )
+       DeleteFile obj
+
+       Local t$=getenv_( "BMK_CC_OPTS" )
+       If t opts:+" "+t
+
+       Local cmd$="gcc"
+       If ExtractExt(src)="cpp" Or ExtractExt(src)="cc" Or ExtractExt(src)="cxx" Or ExtractExt(src)="mm"
+               cmd="g++"
+       Else
+               If CC_WARNINGS opts:+" -Wimplicit-function-declaration"
+       EndIf
+
+       If Not CC_WARNINGS opts:+" -w"
+
+?MacOS
+       If opt_arch="ppc" 
+               opts:+" -arch ppc"
+       Else
+               opts:+" -arch i386"
+       EndIf
+       If macos_version>=$1070                                 'Lion?
+               opts:+" -mmacosx-version-min=10.4"      '...can build for Tiger++
+       Else If macos_version>=$1040                    'Tiger?
+               opts:+" -mmacosx-version-min=10.3"      '...can build for Panther++
+       EndIf
+?Win32
+       If Not mod_opts Or Not mod_opts.hasCCopt("-march")
+               opts:+" -march=pentium"
+       EndIf
+       opts:+" -ffast-math"
+?Linux
+       opts:+" -m32 -mfancy-math-387 -fno-strict-aliasing"
+?
+       If mod_opts
+               If Not mod_opts.hasCCopt("-fexceptions")
+                       opts:+" -fno-exceptions"
+               EndIf
+               opts:+ " " + mod_opts.cc_opts ' BaH
+       Else
+               opts:+" -fno-exceptions"
+       EndIf
+
+       cmd:+opts+" -c -o "+CQuote(obj)+" "+CQuote(src)
+
+       If Sys( cmd )
+               Throw "Build Error: failed to compile "+src
+       EndIf
+End Function
+
+Function CompileBMX( src$,obj$,opts$ )
+       DeleteFile obj
+
+       Local azm$=StripExt(obj)+".s"
+?MacOs
+       Local cmd$=CQuote(BlitzMaxPath()+"/bin/bcc")+opts+" -o "+CQuote(azm)+" "+CQuote(src)
+?Win32
+       Local cmd$=CQuote(BlitzMaxPath()+"/bin/bcc")+opts+" -o "+CQuote(azm)+" "+CQuote(src)
+?Linux 
+       Local cmd$=CQuote(BlitzMaxPath()+"/bin/bcc")+opts+" -o "+CQuote(azm)+" "+CQuote(src)
+?
+       If Sys( cmd )
+               Throw "Build Error: failed to compile "+src
+       EndIf
+?MacOs
+       If opt_arch="x86"
+               If Not USE_NASM
+                       Local cmd$=CQuote(BlitzMaxPath()+"/bin/fasm2as")+" "+CQuote(azm)
+                       If Sys( cmd ) Throw "Fasm2as failed - please contact BRL!"
+               EndIf
+       EndIf
+?
+       Assemble azm,obj
+
+End Function
+
+Function CreateArc( path$ , oobjs:TList )
+       DeleteFile path
+       Local cmd$,t$
+?Win32
+       For t$=EachIn oobjs
+               If Len(cmd)+Len(t)>1000
+                       If Sys( cmd )
+                               DeleteFile path
+                               Throw "Build Error: Failed to create archive "+path
+                       EndIf
+                       cmd=""
+               EndIf
+               If Not cmd cmd="ar -r "+CQuote(path)
+               cmd:+" "+CQuote(t)
+       Next
+?MacOS
+       cmd="libtool -o "+CQuote(path)
+       For Local t$=EachIn oobjs
+               cmd:+" "+CQuote(t)
+       Next
+?Linux
+       For Local t$=EachIn oobjs
+               If Len(cmd)+Len(t)>1000
+                       If Sys( cmd )
+                               DeleteFile path
+                               Throw "Build Error: Failed to create archive "+path
+                       EndIf
+                       cmd=""
+               EndIf
+               If Not cmd cmd="ar -r "+CQuote(path)
+               cmd:+" "+CQuote(t)
+       Next
+?
+       If cmd And Sys( cmd )
+               DeleteFile path
+               Throw "Build Error: Failed to create archive "+path
+       EndIf
+End Function
+
+Function LinkApp( path$,lnk_files:TList,makelib )
+       DeleteFile path
+
+       Local cmd$
+       Local files$
+       Local tmpfile$=BlitzMaxPath()+"/tmp/ld.tmp"
+?MacOS
+       cmd="g++"
+       
+       If opt_arch="ppc" 
+               cmd:+" -arch ppc" 
+       Else
+               cmd:+" -arch i386 -read_only_relocs suppress"
+       EndIf
+
+       If macos_version>=$1070                                 'Lion?
+               cmd:+" -mmacosx-version-min=10.4"       '...can build for Tiger++
+       Else If macos_version>=$1040                    'Tiger?
+               cmd:+" -mmacosx-version-min=10.3"       '...can build for Panther++
+       EndIf
+
+       cmd:+" -o "+CQuote( path )
+       cmd:+" "+CQuote( "-L"+CQuote( BlitzMaxPath()+"/lib" ) )
+
+       If Not opt_dumpbuild cmd:+" -filelist "+CQuote( tmpfile )
+       
+       For Local t$=EachIn lnk_files
+               If opt_dumpbuild Or (t[..1]="-")
+                       cmd:+" "+t 
+               Else
+                       files:+t+Chr(10)
+               EndIf
+       Next
+       cmd:+" -lSystem -framework CoreServices -framework CoreFoundation"
+?Win32
+       cmd=CQuote(BlitzMaxPath()+"/bin/ld.exe")+" -s -stack 4194304"   'symbol stripping enabled
+       If opt_apptype="gui" cmd:+" -subsystem windows"
+       If makelib cmd:+" -shared"
+       
+       cmd:+" -o "+CQuote( path )
+       cmd:+" "+CQuote( "-L"+CQuote( BlitzMaxPath()+"/lib" ) )
+
+       If makelib
+               Local imp$=StripExt(path)+".a"
+               Local def$=StripExt(path)+".def"
+               If FileType( def )<>FILETYPE_FILE Throw "Cannot locate .def file"
+               cmd:+" "+def
+               cmd:+" --out-implib "+imp
+               files:+"~n"+CQuote( BlitzMaxPath()+"/lib/dllcrt2.o" )
+       Else
+               files:+"~n"+CQuote( BlitzMaxPath()+"/lib/crtbegin.o" )
+               files:+"~n"+CQuote( BlitzMaxPath()+"/lib/crt2.o" )
+       EndIf
+
+       'Unholy!!!!!
+       Local xpmanifest$
+       For Local f$=EachIn lnk_files
+               Local t$=CQuote( f )
+               If opt_dumpbuild Or (t[..1]="-" And t[..2]<>"-l")
+                       cmd:+" "+t
+               Else
+                       If f.EndsWith( "/win32maxguiex.mod/xpmanifest.o" )
+                               xpmanifest=t
+                       Else
+                               files:+"~n"+t
+                       EndIf
+               EndIf
+       Next
+
+       If xpmanifest files:+"~n"+xpmanifest
+       
+       cmd:+" "+CQuote( tmpfile )
+
+       files:+"~n-lgdi32 -lwsock32 -lwinmm -ladvapi32"
+       files:+" -lstdc++ -lgcc -lmingwex -lmingw32 -lmoldname -lmsvcrt -luser32 -lkernel32"
+       
+       If Not makelib
+               files:+" "+CQuote( BlitzMaxPath()+"/lib/crtend.o" )
+       EndIf
+       
+       files="INPUT("+files+")"
+?Linux
+
+       cmd="g++"
+       cmd:+" -m32 -s -Os -pthread"
+       cmd:+" -o "+CQuote( path )
+       cmd:+" "+CQuote( tmpfile )
+       cmd:+" -L/usr/lib32"
+       cmd:+" -L/usr/X11R6/lib"
+       cmd:+" -L/usr/lib"
+       cmd:+" -L"+CQuote( BlitzMaxPath()+"/lib" )
+
+       For Local t$=EachIn lnk_files
+               t=CQuote(t)
+               If opt_dumpbuild Or (t[..1]="-" And t[..2]<>"-l")
+                       cmd:+" "+t
+               Else
+                       files:+" "+t
+               EndIf
+       Next
+
+       files="INPUT("+files+")"
+?
+       Local t$=getenv_( "BMK_LD_OPTS" )
+       If t 
+               cmd:+" "+t
+       EndIf
+
+       Local stream:TStream=WriteStream( tmpfile )
+       stream.WriteBytes files.ToCString(),files.length
+       stream.Close
+       
+       If Sys( cmd ) Throw "Build Error: Failed to link "+path
+
+End Function
diff --git a/src/bmk/bmk_zap.bmx b/src/bmk/bmk_zap.bmx
new file mode 100644 (file)
index 0000000..0301fbb
--- /dev/null
@@ -0,0 +1,138 @@
+
+Strict
+
+Import "bmk_modutil.bmx"
+Import "bmk_bank.bmx"
+Import "bmk_modinfo.bmx"
+
+Function Zap( path$,stream:TStream )
+
+       If Not path Return False
+
+       Local name$=StripDir( path )
+       
+       Local skip=False
+       
+       If name[..1]="."
+               skip=True
+       Else If name.ToLower().EndsWith( ".bak" )
+               skip=True
+       EndIf
+       
+       If skip
+               stream.WriteLine ""
+               Return True
+       EndIf
+       
+       Local mode=FileMode( path )
+
+       Select FileType(path)
+       Case FILETYPE_NONE
+               Print "Error zapping file "+path
+               Return
+       Case FILETYPE_FILE
+               Local size=FileSize(path)
+               stream.WriteLine name
+               stream.WriteLine mode
+               stream.WriteLine size
+               Local from_stream:TStream=ReadStream(path)
+               CopyBytes from_stream,stream,size
+               from_stream.Close
+       Case FILETYPE_DIR
+               Local dir$[]=LoadDir( path )
+               Local size=Len( dir )
+               stream.WriteLine name
+               stream.WriteLine -mode
+               stream.WriteLine size
+               For Local t$=EachIn dir
+                       If Not Zap( path+"/"+t,stream ) Return
+               Next
+       End Select
+       
+       Return True
+       
+End Function
+
+Function Unzap( dir$,stream:TStream )
+
+       Local name$=stream.ReadLine()
+       If Not name Return True
+       
+       Local mode=Int( stream.ReadLine() )
+       Local size=Int( stream.ReadLine() )
+
+       Local path$=dir+"/"+name
+       
+       If mode<0
+               mode=-mode
+               CreateDir path
+               For Local k=0 Until size
+                       If Not Unzap( path,stream ) Return
+               Next
+       Else
+               DeleteFile path
+               Local to_stream:TStream=WriteStream(path)
+               CopyBytes stream,to_stream,size
+               to_stream.Close
+       EndIf
+
+       SetFileMode path,mode
+       Return True
+
+End Function
+
+Function ZapMod( name$,stream:TStream )
+
+       Local path$=ModuleInterface( name,"release."+cfg_platform+"."+opt_arch )
+
+       If FileType(path)<>FILETYPE_FILE 
+               Print "Failed to find module"
+               Return
+       EndIf
+       
+       Local src:TSourceFile=ParseSourceFile( path )
+       stream.WriteLine "Module: "+name
+       For Local t$=EachIn src.info
+               stream.WriteLine t
+       Next
+       stream.WriteLine ""
+
+       Local bank:TBank=TBank.Create(0)
+       Local bank_stream:TStream=TBankStream.Create( bank ) 
+       If Not Zap( ModulePath(name),bank_stream ) Throw "Failed to publish module"
+       bank_stream.Close
+       
+       bank=CompressBank( bank )
+       bank_stream=TBankStream.Create( bank )
+       CopyStream bank_stream,stream
+       bank_stream.Close
+
+End Function
+
+Function UnzapMod( stream:TStream )
+
+       Local modinfo:TModInfo=TModInfo.CreateFromStream( stream )
+       
+       Local path$=ModulePath( modinfo.name )
+       If Not CreateDir( path,True ) Throw "Unable to create module directory"
+       DeleteDir path,True
+       
+       Local bank:TBank=TBank.Create(0)
+       Local bank_stream:TStream=TBankStream.Create( bank )
+       CopyStream stream,bank_stream
+       bank_stream.Close
+       
+       bank=UncompressBank( bank )
+       bank_stream=TBankStream.Create( bank )
+       If Not Unzap( ExtractDir(path),bank_stream )
+               Print "Failed to Unzap module"
+               Return
+       EndIf
+       bank_stream.Close
+       
+?MacOS
+       Ranlib path
+?
+       Return True
+
+End Function
diff --git a/src/bmk/macos.icns b/src/bmk/macos.icns
new file mode 100644 (file)
index 0000000..b712495
Binary files /dev/null and b/src/bmk/macos.icns differ
diff --git a/src/docmods/bmxtoker.bmx b/src/docmods/bmxtoker.bmx
new file mode 100644 (file)
index 0000000..3278e2c
--- /dev/null
@@ -0,0 +1,400 @@
+Strict
+
+Import BRL.Map
+Import BRL.Stream
+
+Private
+
+Function ReadTextStream:TStream( url:Object )
+
+       Local format,size,c,d,e
+       Local stream:TStream=ReadStream( url )
+       If Not stream Return
+
+       If Not stream.Eof()
+               c=stream.ReadByte()
+               size:+1
+               If Not stream.Eof()
+                       d=stream.ReadByte()
+                       size:+1
+                       If c=$fe And d=$ff
+                               format=TTextStream.UTF16BE
+                       Else If c=$ff And d=$fe
+                               format=TTextStream.UTF16LE
+                       Else If c=$ef And d=$bb
+                               If Not stream.Eof()
+                                       e=stream.ReadByte()
+                                       size:+1
+                                       If e=$bf format=TTextStream.UTF8
+                               EndIf
+                       EndIf
+               EndIf
+       EndIf
+
+       If format Return TTextStream.Create( stream,format )
+       
+       stream.Close
+       
+       Return ReadStream( url )
+
+End Function
+
+Public
+
+Function TPrint( t$ )
+       Local p
+       For Local i=0 Until t.length
+               If t[i]<256 Continue
+               'unicode char!
+               StandardIOStream.WriteString t[p..i]
+               StandardIOStream.WriteString "&#"+t[i]+";"
+               p=i+1
+       Next
+       Print t[p..]
+End Function
+
+'----- Simple BMX Parser -----
+
+Const T_EOF=           -1
+Const T_EOL=           10
+
+Const T_IDENT=         $10001
+Const T_INTLIT=                $10002
+Const T_FLOATLIT=      $10003
+Const T_STRINGLIT=     $10004
+Const T_STRINGERR=     $10005
+
+Const T_REM=           $20001
+Const T_ENDREM=                $20002
+Const T_FUNCTION=      $20003
+Const T_ENDFUNCTION=$20004
+Const T_TYPE=          $20005
+Const T_ENDTYPE=       $20006
+Const T_CONST=         $20007
+Const T_METHOD=                $20008
+Const T_ENDMETHOD=     $20009
+Const T_GLOBAL=                $2000a
+Const T_INCLUDE=               $2000b ' Added by BaH - 01/06/2006
+Const T_IMPORT=                $2000d
+Const T_FIELD=         $2000e
+Const T_EXTENDS=       $2000f
+Const T_ABSTRACT=      $20010
+Const T_FINAL=         $20011
+Const T_MODULE=                $2000c
+Const T_MODULEINFO=    $20012
+
+Const T_DOTDOT=                $30001
+Const T_ARRAYDECL=     $30002
+
+Const T_KEYWORD=       $40000
+
+Type TIntValue
+       Field value:Int
+End Type
+
+Function IntValue:TIntValue( value )
+       Local t:TIntValue=New TIntValue
+       t.value=value
+       Return t
+End Function
+
+Function IsSpace( char )
+       Return char<=Asc(" ") And char<>Asc("~n")
+End Function
+
+Function IsAlpha( char )
+       Return ( char>=Asc("a") And char<=Asc("z") ) Or ( char>=Asc("A") And char<=Asc("Z") )
+End Function
+
+Function IsNumeric( char )
+       Return char>=Asc("0") And char<=Asc("9")
+End Function
+
+Function IsAlphaNumeric( char )
+       Return IsAlpha( char ) Or IsNumeric( char )
+End Function
+
+Type TBmxToker
+
+       Field _filename:String ' Added by BaH - 25/05/2006
+
+       Field _spc
+       Field _pos,_line$
+       Field _toke,_text$
+       Field _stream:TStream
+       
+       Global _keywords:TMap
+       
+       Method Delete()
+               Close
+       End Method
+
+       Method Bump()
+       
+               If _toke=T_EOF Return _toke
+       
+               If _pos>=_line.length
+                       _pos=0
+                       If _stream.Eof()
+                               _toke=T_EOF
+                               _text=""
+                               Return
+                       EndIf
+                       _line=_stream.ReadLine().Trim()+"~n"
+               EndIf
+               
+               Local from=_pos
+               While _pos<_line.length And IsSpace( _line[_pos] )
+                       _pos:+1
+               Wend
+               
+               If _spc And _pos<>from
+                       _text=_line[from.._pos]
+                       _toke=Asc(" ")
+                       Return _toke
+               EndIf
+               
+               from=_pos
+               Local char=_line[_pos]
+               _pos:+1
+               
+               If char=Asc("'")
+                       _pos=_line.length
+                       _toke=T_EOL
+               Else If char=Asc("~n")
+                       _toke=T_EOL
+               Else If isAlpha(char) Or char=Asc("_")
+                       While IsAlphaNumeric(_line[_pos]) Or _line[_pos]=Asc("_")
+                               _pos:+1
+                       Wend
+                       _toke=T_IDENT
+                       Local id$=_line[from.._pos].ToLower()
+                       If id="end" And _line[_pos]=Asc(" ") And IsAlpha(_line[_pos+1])
+                               Local t_pos=_pos+2
+                               While IsAlphaNumeric(_line[t_pos]) Or _line[t_pos]=Asc("_")
+                                       t_pos:+1
+                               Wend
+                               Local id$="end"+_line[_pos+1..t_pos].ToLower()
+                               Local v:TIntValue=TIntValue( _keywords.ValueForKey( id ) )
+                               If v
+                                       _pos=t_pos
+                                       _toke=v.value
+                               EndIf
+                       EndIf
+                       If _toke=T_IDENT
+                               Local v:TIntValue=TIntValue( _keywords.ValueForKey( id ) )
+                               If v _toke=v.value
+                               If _toke=T_REM
+                                       _text=""
+                                       Repeat
+                                               If _stream.Eof()
+                                                       _pos=0
+                                                       _line=""
+                                                       Return _toke
+                                               EndIf
+                                               _line=_stream.ReadLine().Trim()+"~n"
+                                               If _line[..6].ToLower()="endrem" Or _line[..7].ToLower()="end rem" Exit
+                                               _text:+_line
+                                       Forever
+                                       _pos=_line.length
+                                       Return _toke
+                               Else
+                                       ' Complete lines if they continue onto other lines - BaH 03/09/2006
+                                       If _toke = T_FUNCTION Or _toke = T_METHOD Or _toke = T_CONST Or _toke = T_GLOBAL Or _toke = T_FIELD Then
+                                               If _line.find("..") >= 0 Then
+                                                       _line = getFullLine()
+                                               End If
+                                       End If
+                               EndIf
+                       EndIf
+               Else If IsNumeric(char)
+                       While IsNumeric(_line[_pos])
+                               _pos:+1
+                       Wend
+                       _toke=T_INTLIT
+                       If _line[_pos]=Asc(".")
+                               _pos:+1
+                               While IsNumeric(_line[_pos])
+                                       _pos:+1
+                               Wend
+                               _toke=T_FLOATLIT
+                       EndIf
+               Else If char=Asc("~q")
+                       While _line[_pos]<>Asc("~q") And _line[_pos]<>Asc("~n")
+                               _pos:+1
+                       Wend
+                       If _line[_pos]=Asc("~q")
+                               _pos:+1
+                               _toke=T_STRINGLIT
+                       Else
+                               _toke=T_STRINGERR
+                       EndIf
+               Else
+                       _toke=char
+               EndIf
+               
+               _text=_line[from.._pos]
+               
+               Return _toke
+               
+       End Method
+       
+       ' Completes a line that takes up more than one actual line - BaH 03/09/2006
+       Method getFullLine:String()
+               Local first:Int = True
+               Local fullline:String
+               Local line:String = _line
+               Local pos:Int = 0
+               Local from:Int
+               
+               #loop
+               Repeat
+               
+                       If Not first Then
+                               If _stream.Eof()
+                                       pos=0
+                                       line=""
+                                       Return line
+                               EndIf
+                               line = _stream.ReadLine().Trim()+"~n"
+                       End If
+                       
+                       first = False
+
+                       If line.tolower().Trim() = "rem" Then
+                               Repeat
+                                       If _stream.Eof()
+                                               pos=0
+                                               line=""
+                                               Return fullline
+                                       EndIf
+                                       line = _stream.ReadLine().Trim()+"~n"
+                                       If line[..6].ToLower()="endrem" Or line[..7].ToLower()="end rem" Then
+                                               Continue loop
+                                       End If
+                               Forever
+                       End If
+
+                       pos = 0
+                       from = pos
+                       While pos < line.length And IsSpace( line[pos] )
+                               pos:+1
+                       Wend
+                       
+                       from = pos
+
+                       Local char:Int = line[pos]
+                       pos:+1
+                       While char <> Asc("~n")
+
+                               If char = Asc(".") And line[pos] = Asc(".") Then
+                                       fullline:+ line[from..pos-1]
+                                       Exit
+                               End If
+                               
+                               If char = Asc("'") Then
+                                       Exit
+                               End If
+                               
+                               char=line[pos]
+                               pos:+1 
+                       Wend
+                       
+                       If char = Asc("~n") Then
+                               fullline :+ line[from..pos-1]
+                               Exit
+                       End If
+
+               Forever
+
+               Return fullline
+       End Method
+       
+       Method Curr()
+               Return _toke
+       End Method
+       
+       Method Text$()
+               Return _text
+       End Method
+       
+       Method Line$()
+               Return _line
+       End Method
+       
+       Method Parse$( toke )
+               If Curr()<>toke Throw "Unexpected token"
+               Local t$=Text()
+               Bump
+               Return t
+       End Method
+       
+       Method CParse$( toke )
+               If Curr()<>toke Return
+               Local t$=Text()
+               Bump
+               Return t
+       End Method
+       
+       Method ParseUntil$( toke )
+               Local t$
+               While Curr()<>toke
+                       If Curr()=T_EOF Throw "Unexpected EOF"
+                       t:+Text()
+                       Bump
+               Wend
+               Bump
+               Return t
+       End Method
+       
+       Method Spaces( enable )
+               If enable
+                       _spc:+1
+               Else
+                       _spc:-1
+               EndIf
+       End Method
+       
+       Method Close()
+               If _stream _stream.Close
+               _stream=Null
+       End Method
+       
+       Function CreateKeywords()
+               If _keywords Return
+               Function kw( id$,toke )
+                       _keywords.insert id,IntValue(toke)
+               End Function
+               _keywords=New TMap
+               kw "rem",T_REM
+               kw "endrem",T_ENDREM
+               kw "function",T_FUNCTION
+               kw "endfunction",T_ENDFUNCTION
+               kw "method",T_METHOD
+               kw "endmethod",T_ENDMETHOD
+               kw "const",T_CONST
+               kw "global",T_GLOBAL
+               kw "include",T_INCLUDE ' Added by BaH - 01/06/2006
+               kw "import",T_IMPORT
+               kw "field",T_FIELD
+               kw "type",T_TYPE
+               kw "endtype",T_ENDTYPE
+               kw "extends",T_EXTENDS
+               kw "abstract",T_ABSTRACT
+               kw "final",T_FINAL
+               kw "module",T_MODULE
+               kw "moduleinfo",T_MODULEINFO
+       End Function    
+       
+       Function Create:TBmxToker( url:Object )
+               CreateKeywords
+               Local stream:TStream=ReadTextStream( url )
+               If Not stream Throw "Unable to read stream: "+url.ToString()
+               Local t:TBmxToker=New TBmxToker
+               t._filename = url.ToString() ' Added by BaH - 25/05/2006
+               t._stream=stream
+               t.Bump
+               Return t
+       End Function
+
+End Type
diff --git a/src/docmods/dochistory.bmx b/src/docmods/dochistory.bmx
new file mode 100644 (file)
index 0000000..ce84b6d
--- /dev/null
@@ -0,0 +1,180 @@
+
+Strict
+
+Import "docparser.bmx"
+
+Local docs:TDocs=ParseMods()
+
+docs.Sort
+
+DocModHistory docs
+
+End
+
+If AppArgs.length=2 
+       Select AppArgs[1].ToLower()
+               Case "sync"
+                       SyncDocs docs
+               Case "history"
+                       DocModHistory docs
+       End Select      
+Else
+       DocMods docs
+       SyncDocs docs
+EndIf
+
+' spit out versions.doc format history
+
+
+Function DocModHistory( docs:TDocs )
+
+       Local history$=LoadText("history120.txt")       
+       
+'      Local stdio:TStream=StandardIOStream
+'      StandardIOStream=WriteFile( "commands.html" )
+
+       For Local t:TDocs=EachIn docs.kids      
+               If t.kind<>T_MODULE Continue
+               For Local info$=EachIn t.infos
+                       If info[info.length-8..]<>"Release~q"
+                               If info[..8]="~qHistory" 
+                                       Local h$="+ ("+t.ident+") "+info[10..info.length-1]
+                                       If Not Instr(history,h) TPrint h
+                               EndIf
+                       EndIf
+               Next
+       
+       Next
+
+'      StandardIOStream.Close
+'      StandardIOStream=stdio
+
+End Function
+
+
+Function ParseMods:TDocs()
+
+       Local docs:TDocs=New TDocs
+       
+       Local mods:TList=EnumModules()
+       
+       For Local modid$=EachIn mods
+                       
+               Local ident$=ModuleIdent( modid )
+               Local modDir$=ModulePath( modid )
+               Local bmxFile$=ModuleSource( modid )
+               Local docDir$=modDir+"/doc"
+               
+               If FileType( modDir+"/"+ident+".bmx" )=FILETYPE_FILE
+                       If FileType( docDir )<>FILETYPE_DIR
+                               CreateDir docDir
+                               If FileType( docDir )<>FILETYPE_DIR
+                                       TPrint "Failed to created directory:"+docDir
+                                       Continue
+                               EndIf
+                       EndIf
+
+                       Local toker:TBMXToker=TBMXToker.Create( bmxFile )
+
+                       Local parser:TDocParser=TDocParser.WithToker( toker )
+                       
+                       parser.Parse docs
+       
+                       parser.Close
+
+               EndIf
+               
+       Next
+
+       Return docs
+       
+End Function
+
+Function DocMods( docs:TDocs )
+
+       For Local t:TDocs=EachIn docs.kids
+       
+               If t.kind<>T_MODULE Continue
+               
+               ChangeDir ModulePath( t.ident.tolower() )+"/doc"        'linux fix for "BRL." case problem
+
+               Local stdio:TStream=StandardIOStream
+               StandardIOStream=WriteFile( "commands.html" )
+
+               t.CacheTexts ' pre cache of text for output (allows us to use it for summaries etc) - BaH 03/09/2006
+               t.EmitHtml
+
+               StandardIOStream.Close
+               StandardIOStream=stdio
+       
+       Next
+End Function
+
+Function SyncDocs( docs:TDocs )
+
+       Local comms:TList=New TList
+       Local index:TList=New TList
+       
+       Local stdio:TStream=StandardIOStream
+       StandardIOStream=WriteFile( BlitzMaxPath()+"/doc/bmxmods/navbar.html" )
+       
+       TPrint "<html><head>"
+       TPrint "<link rel=stylesheet type=text/css href='../bmxstyle.css'>"
+       TPrint "<script>function toggle(a){if(a.display!='block')a.display='block';else a.display='none';}</script>"
+       TPrint "</head><body class=navbar>"
+       
+       TPrint "<b>Module reference</b><br>"
+       
+       For Local t:TDocs=EachIn docs.kids
+
+               If t.kind<>T_MODULE Continue
+               
+               Local modid$=t.ident.ToLower()
+               Local modln$=modid.Replace(".","_")
+               Local moddesc$=t.bbdoc[6..].Trim()
+               Local i=moddesc.Find("~n")
+               If i<>-1 moddesc=moddesc[..i]
+               
+               Local url$="../../mod/"+modid.Replace(".",".mod/")+".mod/doc/commands.html"
+               
+               TPrint "<a onClick=toggle("+modln+".style) class=navbig href="+url+" target=main>"+moddesc+"</a><br>"
+               TPrint "<div id="+modln+" class=entries>"
+               For Local p:TDocs=EachIn t.kids
+                       ' kind is Type and is not doc'd and there are no doc'd kids
+                       If p.kind = T_TYPE And (Not p.bbdoc And p.kids.count() = 0) Then
+                               Continue
+                       End If
+                       Local turl$=url+"#"+p.ident
+                       TPrint "&nbsp;<a class=navsmall href="+turl+" target=main>"+p.ident+"</a><br>"
+                       index.AddLast p.ident+":"+turl
+                       Local i=p.proto.Find( " " )
+                       If i<>-1 comms.AddLast p.proto[i+1..].Trim()+"|"+turl[5..]
+               Next
+               TPrint "</div>"
+
+       Next
+       
+       TPrint "<br>"
+       TPrint "<b>Alphabetic index</b><br>"
+
+       Local arr:Object[]=index.ToArray()
+       arr.Sort
+       For Local link$=EachIn arr
+               Local i=link.Find( ":" )
+               If i=-1 Throw "chunks"
+               Local ident$=link[..i],url$=link[i+1..]
+               TPrint "<a class=navsmall href="+url+" target=main>"+ident+"</a><br>"
+       Next
+       
+       TPrint "</body></html>"
+       
+       StandardIOStream.Close
+       StandardIOStream=WriteStream( BlitzMaxPath()+"/doc/bmxmods/commands.txt" )
+       For Local t$=EachIn comms
+               TPrint t
+       Next
+       StandardIOStream.Close
+       StandardIOStream=stdio
+
+End Function
+
diff --git a/src/docmods/docmods.bmx b/src/docmods/docmods.bmx
new file mode 100644 (file)
index 0000000..b972a6f
--- /dev/null
@@ -0,0 +1,157 @@
+
+Rem
+
+Note: docmods is now only used to build 3rd party modules.
+
+BRL, MAXGUI and PUB mods are built by new makedocs.
+
+End Rem
+
+Strict
+
+Framework brl.basic
+
+Import "docparser.bmx"
+
+CreateDir BlitzMaxPath()+"/doc/bmxmods",True
+
+Local docs:TDocs=ParseMods()
+
+docs.Sort
+
+If AppArgs.length=2 And AppArgs[1].ToLower()="sync"
+       SyncDocs docs
+Else
+       DocMods docs
+       SyncDocs docs
+EndIf
+
+Function ParseMods:TDocs()
+
+       Local docs:TDocs=New TDocs
+       
+       Local mods:TList=EnumModules()
+       
+       For Local modid$=EachIn mods
+
+               If modid.StartsWith( "brl." ) Or modid.StartsWith( "pub." ) Or modid.StartsWith( "maxgui." ) Continue
+                       
+               Local ident$=ModuleIdent( modid )
+               Local modDir$=ModulePath( modid )
+               Local bmxFile$=ModuleSource( modid )
+               Local docDir$=modDir+"/doc"
+               
+               If FileType( modDir+"/"+ident+".bmx" )=FILETYPE_FILE
+                       If FileType( docDir )<>FILETYPE_DIR
+                               CreateDir docDir
+                               If FileType( docDir )<>FILETYPE_DIR
+                                       Print "Failed to created directory:"+docDir
+                                       Continue
+                               EndIf
+                       EndIf
+
+                       Local toker:TBMXToker=TBMXToker.Create( bmxFile )
+
+                       Local parser:TDocParser=TDocParser.WithToker( toker )
+                       
+                       parser.Parse docs
+       
+                       parser.Close
+
+               EndIf
+               
+       Next
+
+       Return docs
+       
+End Function
+
+Function DocMods( docs:TDocs )
+
+       For Local t:TDocs=EachIn docs.kids
+       
+               If t.kind<>T_MODULE Continue
+               
+               ChangeDir ModulePath( t.ident.tolower() )+"/doc"        'linux fix for "BRL." case problem
+
+               Local stdio:TStream=StandardIOStream
+               StandardIOStream=WriteFile( "commands.html" )
+
+               t.CacheTexts ' pre cache of text for output (allows us to use it for summaries etc) - BaH 03/09/2006
+               t.EmitHtml
+
+               StandardIOStream.Close
+               StandardIOStream=stdio
+       
+       Next
+End Function
+
+Function SyncDocs( docs:TDocs )
+
+       Local comms:TList=New TList
+       Local index:TList=New TList
+       
+       Local stdio:TStream=StandardIOStream
+       StandardIOStream=WriteFile( BlitzMaxPath()+"/doc/bmxmods/navbar.html" )
+       
+       TPrint "<html><head>"
+       TPrint "<link rel=stylesheet type=text/css href='../bmxstyle.css'>"
+       TPrint "<script>function toggle(a){if(a.display!='block')a.display='block';else a.display='none';}</script>"
+       TPrint "</head><body class=navbar>"
+       
+       TPrint "<b>Module reference</b><br>"
+       
+       For Local t:TDocs=EachIn docs.kids
+
+               If t.kind<>T_MODULE Continue
+               
+               Local modid$=t.ident.ToLower()
+               Local modln$=modid.Replace(".","_")
+               Local moddesc$=t.bbdoc[6..].Trim()
+               Local i=moddesc.Find("~n")
+               If i<>-1 moddesc=moddesc[..i]
+               
+               Local url$="../../mod/"+modid.Replace(".",".mod/")+".mod/doc/commands.html"
+               
+               TPrint "<a onClick=toggle("+modln+".style) class=navbig href="+url+" target=main>"+moddesc+"</a><br>"
+               TPrint "<div id="+modln+" class=entries>"
+               For Local p:TDocs=EachIn t.kids
+                       ' kind is Type and is not doc'd and there are no doc'd kids
+                       If p.kind = T_TYPE And (Not p.bbdoc And p.kids.count() = 0) Then
+                               Continue
+                       End If
+                       Local turl$=url+"#"+p.ident
+                       TPrint "&nbsp;<a class=navsmall href="+turl+" target=main>"+p.ident+"</a><br>"
+                       index.AddLast p.ident+":"+turl
+                       Local i=p.proto.Find( " " )
+                       If i<>-1 comms.AddLast p.proto[i+1..].Trim()+"|"+turl[5..]
+               Next
+               TPrint "</div>"
+
+       Next
+       
+       TPrint "<br>"
+       TPrint "<b>Alphabetic index</b><br>"
+
+       Local arr:Object[]=index.ToArray()
+       
+       arr.Sort
+       For Local link$=EachIn arr
+               Local i=link.Find( ":" )
+               If i=-1 Throw "chunks"
+               Local ident$=link[..i],url$=link[i+1..]
+               TPrint "<a class=navsmall href="+url+" target=main>"+ident+"</a><br>"
+       Next
+       
+       TPrint "</body></html>"
+       
+       StandardIOStream.Close
+       StandardIOStream=WriteStream( BlitzMaxPath()+"/doc/bmxmods/commands.txt" )
+       For Local t$=EachIn comms
+               Print t
+       Next
+       StandardIOStream.Close
+       StandardIOStream=stdio
+
+End Function
+
diff --git a/src/docmods/docparser.bmx b/src/docmods/docparser.bmx
new file mode 100644 (file)
index 0000000..ea4b0ec
--- /dev/null
@@ -0,0 +1,683 @@
+Strict
+
+Import BRL.StandardIO
+Import BRL.MaxUtil
+
+Import "bmxtoker.bmx"
+
+Function FormatTags( t$ Var,bbTag$,htmlTag$ )
+       Local i
+       Repeat
+               i=t.Find( bbTag,i )
+               If i=-1 Exit
+               
+               If i And t[i-1]>32
+                       i:+1
+                       Continue
+               EndIf
+
+               Local e         
+               If i<t.length-1 And t[i+1]=Asc("{")
+                       Local e=t.Find( "}",i+2 )
+                       If e=-1 
+                               i:+2
+                               Continue
+                       EndIf
+                       Local q$="<"+htmlTag+">"+t[i+2..e]+"</"+htmlTag+">"
+                       t=t[..i]+q+t[e+1..]
+                       i:+q.length
+                       
+               Else
+                       e=i+1
+                       While e<t.length
+                               Local c=t[e]
+                               If c=Asc(".") And e+1<t.length And IsAlpha( t[e+1] )
+                                       e:+2
+                                       Continue
+                               EndIf
+                               If c = Asc(";") Return
+                               If c<>Asc("_") And Not IsAlphaNumeric(c) Exit
+                               e:+1
+                       Wend
+                       Local q$="<"+htmlTag+">"+t[i+1..e]+"</"+htmlTag+">"
+                       t=t[..i]+q+t[e..]
+                       i:+q.length
+               EndIf
+       Forever
+End Function
+
+Function FindIdent( pre$,text$,i Var,e Var )
+
+       i=text.Find( pre,i )
+       
+       If i=-1 Return False
+       
+       If i>0 And text[i-1]>32 Return False
+       
+       e=i+1
+       While e<text.length
+               Local c=text[e]
+               If c=Asc(".") And e+1<text.length And IsAlpha( text[e+1] )
+                       e:+2
+                       Continue
+               EndIf
+               If c<>Asc("_") And Not IsAlphaNumeric(c) Exit
+               e:+1
+       Wend
+       Return True
+End Function
+
+Function FormatText( t$ Var )
+
+       If t.length And IsAlphaNumeric( t[t.length-1] ) t:+"."
+
+       Local i,e
+
+       'do links
+       i=0
+       While FindIdent( "#",t,i,e )
+       
+               While e<t.length-1 And t[e]=Asc(".") And IsAlpha( t[e+1] )
+                       e:+2
+                       While e<t.length And IsAlpha(t[e])
+                               e:+1
+                       Wend
+               Wend
+               
+               Local id$=t[i+1..e],q=id.Find("."),ln$
+
+               If q=-1
+                       ln="<a href=#"+id+">"+id+"</a>"
+               Else
+                       ln="<a href=../../../"
+                       Repeat
+                               ln:+id[..q]+".mod/"
+                               id=id[q+1..]
+                               q=id.Find(".")
+                       Until q=-1
+                       ln:+"doc/commands.html#"+id+">"+id+"</a>"
+               EndIf
+                       
+               t=t[..i]+ln+t[e..]
+               i:+ln.length
+       Wend
+       
+       FormatTags t,"@","b"
+       FormatTags t,"%","i"
+       FormatTags t,"&","pre"
+       
+       'do tables
+       i=0
+       Repeat
+               i=t.Find( "~n[",i )
+               If i=-1 Exit
+               
+               Local i2=t.Find( "~n]",i+3 )
+               If i2=-1 Exit
+               
+               Local q$=t[i+2..i2]
+
+               q=q.Replace( "* ","</td></tr><tr><td>" )
+               q=q.Replace( " | ","</td><td>" )
+               
+               q="~n<table><tr><td>"+q+"</table>~n"
+               
+               t=t[..i]+q+t[i2+2..]
+               i:+q.length
+
+       Forever
+       
+       'paras
+       t=t.Replace( "~n~n","~n<p>~n" )
+       
+End Function
+
+Type TDocs
+
+       Field kind              'T_CONST, T_GLOBAL etc
+       Field ident$    'identifier
+       Field proto$    'Global/Function etc text
+       Field bbdoc$    'rem/endrem bbdoc: text
+       Field infos:TList=New TList     'ModuleInfo's
+       Field imports:TList = New TList ' Added by BaH - 25/05/2006
+       Field parent:TDocs ' Added by BaH - 25/05/2006
+       Field textCache:TTextCache
+       
+       Field kids:TList=New TList
+       
+       Method Sort()
+               kids.Sort
+               For Local t:TDocs=EachIn kids
+                       t.Sort
+               Next
+       End Method
+       
+       ' Added by BaH - 25/05/2006
+       ' Checks for extra references to the same imports...
+       Method containsImport:Int(_file:String)
+               If imports.contains(_file) Then
+                       Return True
+               End If
+               If parent <> Null Then
+                       Return parent.containsImport(_file)
+               End If
+               
+               Return False
+       End Method
+       
+       Method Compare( with:Object )
+               Local t:TDocs=TDocs(with)
+
+               If kind=t.kind
+                       If kind=T_MODULE 
+                               Return bbdoc.ToLower().Compare( t.bbdoc.ToLower() )
+                       EndIf
+                       Return ident.ToLower().Compare( t.ident.ToLower() )
+               EndIf
+
+               If kind=T_MODULE Return -1
+               If t.kind=T_MODULE Return 1
+               
+               If kind=T_CONST Return -1
+               If t.kind=T_CONST Return 1
+
+               If kind=T_GLOBAL Return -1
+               If t.kind=T_GLOBAL Return 1
+               
+               If kind=T_FIELD Return -1
+               If t.kind=T_FIELD Return 1
+
+               If kind=T_METHOD Return -1
+               If t.kind=T_METHOD Return 1
+
+               If kind=T_FUNCTION Return -1
+               If t.kind=T_FUNCTION Return 1
+               
+               If kind=T_TYPE Return -1
+               If t.kind=T_TYPE Return 1
+               
+               If kind=T_EOL Return -1
+               If t.kind=T_EOL Return 1
+               
+               Throw "OOps!"
+               
+       End Method
+       
+       Method CacheTexts()
+               If textCache = Null Then
+                       textCache = TTextCache.Create(bbdoc, kind)
+               
+                       If Not kids.IsEmpty()
+                               Local tkind=0
+                               For Local doc:TDocs=EachIn kids
+                                       doc.CacheTexts()
+                               Next
+                       EndIf
+
+               End If
+
+       End Method
+       
+       Method EmitHtml$(summary:Int = False)
+               Local example$
+
+               Local stream:TStream=ReadStream( ident+".bmx" )
+               If stream
+                       While Not stream.Eof()
+                               example:+stream.ReadLine()+"~n"
+                       Wend
+                       stream.Close
+                       example=example.Trim()
+               EndIf
+               
+               If Not summary Then
+                       Select kind
+                       Case 0
+                       Case T_MODULE
+                               TPrint "<html><head><title>"+textCache.shortdesc+" reference</title>"
+                               TPrint "<link rel=stylesheet Type=text/css href='../../../../doc/bmxstyle.css'>"
+                               TPrint "</head><body>"
+                               Local n_consts
+                               Local n_globals
+                               Local n_functions
+                               Local n_types
+                               Local n_keywords:Int
+                               For Local t:TDocs=EachIn kids
+                                       Select t.kind
+                                       Case T_CONST n_consts:+1
+                                       Case T_GLOBAL n_globals:+1
+                                       Case T_FUNCTION n_functions:+1
+                                       Case T_TYPE
+                                               ' Type is doc'd or there are doc'd kids
+                                               If t.bbdoc Or t.kids.count() > 0 Then
+                                                       n_types:+1
+                                               End If
+                                       Case T_EOL n_keywords:+1
+                                       End Select
+                               Next
+                               
+                               TPrint "<table width=100% cellspacing=0><tr align=center><td class=small>&nbsp;</td>"
+                               TPrint "<td class=small width=1%><b>"+ident+":</b></td>"
+                               If n_consts TPrint "<td class=small width=1%><a href=#consts class=small>Constants</a></td>"
+                               If n_globals TPrint "<td class=small width=1%><a href=#globals class=small>Globals</a></td>"
+                               If n_functions TPrint "<td class=small width=1%><a href=#functions class=small>Functions</a></td>"
+                               If n_types TPrint "<td class=small width=1%><a href=#types class=small>Types</a></td>"
+                               If n_keywords TPrint "<td class=small width=1%><a href=#keywords class=small>Keywords</a></td>"
+                               
+                               If Not infos.IsEmpty()
+                                       TPrint "<td class=small width=1%><a href=#modinfo class=small>Modinfo</a></td>"
+                               EndIf
+                               
+                               Local t$=ModuleSource( ident.ToLower() )
+                               Local i=t.Find( "/mod/" )
+                               If i<>-1
+                                       t="../../../.."+t[i..]
+                                       TPrint "<td class=small width=1%><a href='"+t+"' class=small>Source</a></td>"
+                               EndIf
+                               TPrint "<td class=small>&nbsp;</td></tr></table>"
+                               
+                               Local stream:TStream=ReadStream( "intro.bbdoc" )
+                               
+                               If stream
+                                       TPrint "<h1>"+textCache.shortdesc+"</h1>"
+                                       If textCache.longdesc TPrint textCache.longdesc.Trim()
+                               Else
+                                       stream=ReadStream( "intro.html" )
+                                       If Not stream
+                                               TPrint "<h1>"+textCache.shortdesc+"</h1>"
+                                               If textCache.longdesc TPrint textCache.longdesc.Trim()
+                                       EndIf
+                               EndIf
+                               
+                               If stream
+                                       Local intro$
+                                       While Not stream.Eof()
+                                               intro:+stream.ReadLine()+"~n"
+                                       Wend
+                                       Local i=intro.Find("<body>")
+                                       If i<>-1
+                                               intro=intro[i+6..]
+                                               i=intro.find("</body>")
+                                               If i<>-1 intro=intro[..i]
+                                       EndIf
+                                       stream.close
+                                       intro=intro.Trim()
+                                       FormatText intro
+                                       TPrint intro
+                               EndIf
+       
+                               ' Show summaries
+                               If Not kids.IsEmpty()
+                                       Local s:String = Null
+                                       Local tkind=0
+                                       Local count:Int = 0
+                                       For Local doc:TDocs=EachIn kids
+                                               ' kind is Type and is not doc'd and there are no doc'd kids
+                                               If doc.kind = T_TYPE And (Not doc.bbdoc And doc.kids.count() = 0) Then
+                                                       Continue
+                                               End If
+                                       
+                                               s = "<table class=doc width=100%>"
+                                               
+                                               If kind<>T_TYPE And doc.kind<>tkind
+                                                       count = 0
+                                                       If tkind <> 0 Then
+                                                               If tkind = T_CONST Or tkind = T_GLOBAL Or tkind = T_EOL Then
+                                                                       TPrint "</td></tr>"
+                                                               End If
+                                                               TPrint "</table>"
+                                                       End If
+                                                       Select doc.kind
+                                                               Case T_CONST TPrint "<h2><a name=consts></a>Constants Summary</h2>" + s + "<tr><td colspan=2>"
+                                                               Case T_GLOBAL TPrint "<h2><a name=globals></a>Globals Summary</h2>" + s + "<tr><td colspan=2>"
+                                                               Case T_FUNCTION TPrint "<h2><a name=functions></a>Functions Summary</h2>" + s
+                                                               Case T_TYPE TPrint "<h2><a name=types></a>Types Summary</h2>" + s
+                                                               Case T_EOL TPrint "<h2><a name=keywords></a>Keywords Summary</h2>" + s + "<tr><td colspan=2>"
+                                                               Default
+                                                                       Continue
+                                                       End Select
+                                                       tkind=doc.kind
+                                               EndIf
+                                               count:+ 1
+                                               If count > 1 Then
+                                                       If tkind = T_CONST Or tkind = T_GLOBAL Or tkind = T_EOL Then
+                                                               TPrint ", "
+                                                       End If
+                                               End If 
+                                               doc.EmitHtml(True)
+                                       Next
+                                       If s Then
+                                               TPrint "</table>"
+                                       End If
+                               EndIf
+                                               
+                       Default
+                               TPrint "<table class=doc width=100% cellspacing=3 id="+ident+">"
+                               TPrint "<tr><td class=doctop colspan=2>"+proto+"</td></tr>"
+                               If textCache.returns
+                                       TPrint "<tr><td class=docleft width=1%>Returns</td><td class=docright>"+textCache.returns+"</td></tr>"
+                               EndIf
+                               If textCache.shortdesc
+                                       TPrint "<tr><td class=docleft width=1%>Description</td><td class=docright>"+textCache.shortdesc+"</td></tr>"
+                               EndIf
+                               If textCache.longdesc
+                                       TPrint "<tr><td class=docleft width=1%>Information</td><td class=docright>"+textCache.longdesc+"</td></tr>"
+                               EndIf
+                               If example
+                                       TPrint "<tr><td class=docleft width=1%><a href="+ident+".bmx class=small>Example</a></td><td class=docright><pre>"+example+"</pre></td></tr>"
+                               EndIf
+                               TPrint "</table>"
+                       End Select
+
+                       If kind = T_TYPE Then
+                               ' Show summaries
+                               If Not kids.IsEmpty()
+                                       Local s:String = Null
+                                       Local tkind=0
+                                       Local count:Int = 0
+                                       For Local doc:TDocs=EachIn kids
+                                               s = "<table class=doc width=90% align=center>" + ..
+                                                       "<tr ><th class=doctop colspan=2 align=left>"
+                                               If doc.kind<>tkind
+                                                       count = 0
+                                                       If tkind <> 0 Then
+                                                               If tkind = T_CONST Or tkind = T_GLOBAL Or tkind = T_EOL Or tkind = T_FIELD Then
+                                                                       TPrint "</td></tr>"
+                                                               End If
+                                                               TPrint "</table>"
+                                                       End If
+                                                       Select doc.kind
+                                                               Case T_CONST TPrint s + "<a name=" + ident + "_consts></a>Constants Summary</th></tr><tr><td colspan=2>"
+                                                               Case T_FIELD TPrint s + "<a name=" + ident + "_fields></a>Fields Summary</th></tr><tr><td colspan=2>"
+                                                               Case T_GLOBAL TPrint s + "<a name=" + ident + "_globals></a>Globals Summary</th></tr><tr><td colspan=2>"
+                                                               Case T_FUNCTION TPrint s + "<a name=" + ident + "_functions></a>Functions Summary</th></tr>"
+                                                               Case T_METHOD TPrint s + "<a name=" + ident + "_methods></a>Methods Summary</th></tr>"
+                                                               Default
+                                                                       Continue
+                                                       End Select
+                                                       tkind=doc.kind
+                                               EndIf
+                                               count:+ 1
+                                               If count > 1 Then
+                                                       If tkind = T_CONST Or tkind = T_GLOBAL Or tkind = T_FIELD Then
+                                                               TPrint ", "
+                                                       End If
+                                               End If 
+                                               doc.EmitHtml(True)
+                                       Next
+                                       If s Then
+                                               TPrint "</table>"
+                                       End If
+                               EndIf
+                       End If
+
+                       If Not kids.IsEmpty()
+                               Local tkind=0
+                               For Local doc:TDocs=EachIn kids
+                                       ' kind is Type and is not doc'd and there are no doc'd kids
+                                       If doc.kind = T_TYPE And (Not doc.bbdoc And doc.kids.count() = 0) Then
+                                               Continue
+                                       End If
+
+                                       If kind<>T_TYPE And doc.kind<>tkind
+                                               TPrint "<h2"
+                                               Select doc.kind
+                                               Case T_CONST TPrint " id=constsdet>Constants"
+                                               Case T_GLOBAL TPrint " id=globalsdet>Globals"
+                                               Case T_FUNCTION TPrint " id=functionsdet>Functions"
+                                               Case T_TYPE TPrint " id=typesdet>Types"
+                                               Case T_FIELD TPrint ">Fields"
+                                               Case T_METHOD TPrint ">Methods"
+                                               Case T_EOL TPrint ">Keywords"
+                                               End Select
+                                               TPrint "</h2>"
+                                               tkind=doc.kind
+                                       EndIf
+                                       doc.EmitHtml
+                                       If kind<>T_TYPE TPrint "<br>"
+                               Next
+                       EndIf                   
+               Else
+                       Select kind
+                               Case T_CONST, T_GLOBAL, T_FIELD, T_EOL
+                                       TPrint "<a href=#" + ident + ">" + ident + "</a>"
+                               Case T_FUNCTION, T_METHOD, T_TYPE
+                                       TPrint "<tr><td class=docleft width=1%><a href=#" + ident + ">" + ident + "</a></td><td class=docright>"
+                                       If textCache.shortdesc
+                                               TPrint textCache.shortdesc
+                                       Else
+                                               TPrint "&nbsp;"
+                                       EndIf
+                                       TPrint "</td></tr>"
+                       End Select
+               End If
+               
+
+               
+               Select kind
+               Case T_MODULE
+                       If Not infos.IsEmpty()
+                               TPrint "<h2 id=modinfo>Module Information</h2>"
+                               TPrint "<table width=100%>"
+                               For Local t$=EachIn infos
+                                       t=t[1..t.length-1]
+                                       If Not t Continue
+                                       Local i=t.Find(":")
+                                       If i=-1 Continue
+                                       Local key$=t[..i].Trim()
+                                       Local val$=t[i+1..].Trim()
+                                       TPrint "<tr><th width=1%>"+key+"</th><td>"+val+"</td></tr>"
+                               Next
+                       EndIf
+                       TPrint "</body></html>"
+               End Select
+               
+       End Method
+
+End Type
+
+Type TDocParser
+
+       Field toker:TBMXToker
+       
+       Method Close()
+               If Not toker Return
+               toker.Close
+               toker=Null
+       End Method
+
+       ' Added by BaH - 25/05/2006
+       Method processImport(parent:TDocs, txt:String)
+       
+               If txt.find(".bmx") > 0 Then
+       
+                       Local importFile:String = ExtractDir(toker._filename) + "/" + txt[1..txt.length-1]
+                       Local _file:String = StripDir(importFile).toLower()
+                       
+                       If Not parent.containsImport(_file) Then
+                               If FileType(importFile) = 1 Then ' exists !
+                                       parent.imports.AddLast(_file)
+                                       Local _toker:TBMXToker=TBMXToker.Create(importFile)
+                                       Local _parser:TDocParser=TDocParser.WithToker(_toker)
+                                       _parser.Parse parent
+                                       _parser.Close
+                               End If
+                       End If
+               End If
+       
+       End Method
+
+       Method Parse( parent:TDocs )
+       
+               If Not toker Throw "closed"
+       
+               While toker.Curr()<>T_EOF
+
+                       If toker.Curr()=T_ENDTYPE 
+                               If parent.kind=T_TYPE Return
+                               toker.Bump
+                               Continue
+                       EndIf
+
+                       ' Added by BaH - 25/05/2006, modified 01/06/2006
+                       If toker.Curr()=T_IMPORT Or toker.Curr()=T_INCLUDE Then
+                               If parent.kind=T_MODULE
+                                       If toker.Bump()=T_STRINGLIT
+                                               processImport(parent, Toker.Text())
+                                       End If
+                               End If
+                       End If
+                       
+                       If toker.Curr()=T_MODULEINFO
+                               If parent.kind=T_MODULE 
+                                       If toker.Bump()=T_STRINGLIT
+                                               parent.infos.AddLast toker.Text()
+                                       EndIf
+                               EndIf
+                               toker.Bump
+                               Continue
+                       EndIf
+               
+                       Local skip:Int = False
+                       Local kind:Int
+                       Local bbdoc$
+                       
+                       If toker.Curr()<>T_REM 
+                               kind = toker.Bump()
+                               
+                               ' Fix to stop fields / methods etc appearing at top of docs if type not doc'd.
+                               If kind = T_TYPE Then
+                                       skip = True
+                               Else
+                                       Continue
+                               End If
+                       EndIf
+                       
+                       If Not skip Then
+                               If toker.Text()[..6]<>"bbdoc:"
+                                       toker.Bump
+                                       Continue
+                               EndIf
+                               bbdoc = toker.Text()
+
+                       
+                               kind=toker.Bump()
+                               If kind<>T_CONST And kind<>T_GLOBAL And kind<>T_FUNCTION And kind<>T_METHOD..
+                               And kind<>T_MODULE And kind<>T_TYPE And kind<>T_FIELD And kind<>T_EOL
+                                       toker.Bump
+                                       Continue
+                               EndIf
+                       End If
+                       
+                       Local ident$,proto$
+                       If kind=T_EOL
+                               Local i=bbdoc.Find( "keyword:" )
+                               If i=-1 Continue
+                               ident=bbdoc[i+8..].Replace( "~q","" )
+                               proto="Keyword "+ident.Trim()
+                       Else
+                               proto=toker.Line()
+                               If toker.Bump()<>T_IDENT Continue
+                               ident=toker.Text()
+                               If toker.Bump()=Asc(".") And toker.Bump()=T_IDENT
+                                       ident:+"."+toker.Text()
+                               EndIf
+                               toker.Bump
+                               Select kind
+                               Case T_CONST,T_GLOBAL
+                                       Local i=proto.Find( "=" )
+                                       If i<>-1 proto=proto[..i]
+                               Case T_FUNCTION,T_METHOD
+                                       Local i=proto.Find( "=" )
+                                       While i<>-1 And proto.Find( ")",i+1 )<>-1
+                                               i=proto.Find( "=",i+1 )
+                                       Wend
+                                       If i<>-1 proto=proto[..i]
+                                       
+                                       
+                                       i=proto.toLower().Find( "nodebug" )
+                                       While i<>-1 And proto.Find( ")",i+1 )<>-1
+                                               i=proto.toLower().Find( "nodebug",i+1 )
+                                       Wend
+                                       If i<>-1 proto=proto[..i]
+                                       
+                               End Select
+                       EndIf
+                       
+                       'got a valid Doc!
+                       Local docs:TDocs=New TDocs
+                       docs.kind=kind
+                       docs.ident=ident.Trim()
+                       docs.proto=proto.Trim()
+                       docs.bbdoc=bbdoc.Trim()
+                       docs.parent = parent ' Added by BaH - 25/05/2006
+
+                       parent.kids.AddLast docs
+                       
+                       If kind=T_MODULE Or kind=T_TYPE
+                               Parse docs
+                       EndIf
+                       
+               Wend
+       
+       End Method
+       
+       Function WithToker:TDocParser( toker:TBmxToker )
+       
+               Local t:TDocParser=New TDocParser
+               t.toker=toker
+               Return t
+
+       End Function
+       
+End Type
+
+Type TTextCache
+       Field returns:String
+       Field keyword:String
+       Field shortdesc:String
+       Field longdesc:String
+       Field parameters:TList = New TList
+
+       Function Create:TTextCache(bbdoc:String, kind:Int)
+               Local this:TTextCache = New TTextCache
+               
+               Local d:String = bbdoc
+               
+               Local i=d.Find("~n")
+               If i=-1 i=d.length
+               this.shortdesc=d[6..i].Trim()
+               d=d[i+1..].Trim()
+               If kind<>T_MODULE 
+                       FormatText this.shortdesc
+               EndIf
+               
+            If d.Find( "returns:" )=0
+                       Local i=d.Find("~n")
+                       If i=-1 i=d.length
+                       this.returns=d[8..i].Trim()
+                       d=d[i+1..].Trim()
+                       FormatText this.returns
+               Else If d.Find( "keyword:" )=0
+                       Local i=d.Find("~n")
+                       If i=-1 i=d.length
+                       this.keyword=d[8..i].Trim()
+                       d=d[i+1..].Trim()
+                       FormatText this.keyword
+               EndIf
+               While d.Find("parameter:") = 0
+                       Local i=d.Find("~n")
+                       If i=-1 i=d.length
+                       Local param:String=d[10..i].Trim()
+                       d=d[i+1..].Trim()
+                       FormatText param
+                       this.parameters.addLast(param)
+               Wend
+               If d.Find( "about:" )=0
+                       this.longdesc=d[6..].Trim()
+                       FormatText this.longdesc
+               EndIf   
+               
+               Return this
+       End Function
+End Type
\ No newline at end of file
diff --git a/src/fasm2as/fasm2as.bmx b/src/fasm2as/fasm2as.bmx
new file mode 100644 (file)
index 0000000..1184d0b
--- /dev/null
@@ -0,0 +1,245 @@
+
+Strict
+
+Framework brl.basic
+
+Import Pub.StdC
+
+Try
+
+ChangeDir LaunchDir
+
+If AppArgs.length<>2 And AppArgs.length<>3
+       Print "Command line error"
+       End
+EndIf
+
+Local in:TStream=CreateBankStream( LoadBank( AppArgs[1] ) ),out:TStream
+
+If AppArgs.length=3
+       out=WriteStream( AppArgs[2] )
+Else
+       out=WriteStream( AppArgs[1] )
+EndIf
+
+If Not out Throw "Failed to create output stream"
+
+While Not in.Eof()
+
+       Local line$=in.ReadLine()
+       
+       Local t_line$=line
+       
+       If line And line[0]=9
+               Local i=line.Find( Chr(9),1 )
+               If i<>-1
+                       Local sz
+                       Local op$=line[1..i]
+                       Local args$=line[i+1..]
+                       Select op
+                       Case "db"
+                               op=".byte"
+                               If args[..1]="~q" And args[args.length-3..]="~q,0"
+                                       op=".asciz"
+                                       args="~q"+args[1..args.length-3]+"~q"
+                               EndIf
+                       Case "dw"
+                               op=".short"
+                       Case "dd"
+                               op=".long"
+                       Case "extrn"
+                               op=".reference"
+                       Case "public"
+                               op=".globl"
+                       Case "align"
+                               op=".align"
+                       Case "file"
+                               If args[..1]="~q" And args[args.length-1..]="~q"
+                                       args=args[1..args.length-1]
+                               EndIf
+                               Local r:TStream=ReadStream( args ),n
+                               If Not r Throw "Unable to open file "+args
+                               Local buf:Byte[64]
+                               Repeat
+                                       Local n=r.Read( buf,64 )
+                                       If Not n Exit
+                                       Local t$="~t.byte~t"+buf[0]
+                                       For Local i=1 Until n
+                                               t:+","+buf[i]
+                                       Next
+                                       WriteString out,t
+                                       WriteString out,"~n"
+                               Forever
+                               r.Close
+                               op=""
+                       Case "section"
+                               op="."+args
+                               args=""
+                       Default
+                               Local i=args.Find( "," )
+                               If i=-1
+                                       sz=FixArg( args,op )
+                                       If sz And op="call" args="*"+args
+                               Else
+                                       Local arg2$=args[..i]
+                                       Local arg1$=args[i+1..]
+                                       Local sz1=FixArg( arg1 )
+                                       Local sz2=FixArg( arg2 )
+                                       sz=sz1
+                                       If sz2 sz=sz2
+                                       Select op
+                                       Case "lea"
+                                               sz=0
+                                       Case "movzx","movsx"
+                                               Local s$
+                                               Select sz
+                                               Case 1
+                                                       s="b"
+                                               Case 2
+                                                       s="w"
+                                               Case 0
+                                                       Select arg1
+                                                       Case "%al","%bl","%cl","%dl"
+                                                               s$="b"
+                                                       Case "%ax","%bx","%cx","%dx","%bp","%sp","%si","%di"
+                                                               s$="w"
+                                                       End Select
+                                               End Select
+                                               op=op[..4]+s+"l"
+                                               sz=0
+                                       Case "fdiv","fsub"
+                                               If arg1="%st(0)" And arg2[..3]="%st" op=op[..4]+"r"
+                                       Case "fdivp","fsubp"
+                                               If arg1="%st(0)" And arg2[..3]="%st" op=op[..4]+"rp"
+                                       Case "fdivr","fsubr"
+                                               If arg1="%st(0)" And arg2[..3]="%st" op=op[..4]
+                                       Case "fdivrp","fsubrp"
+                                               If arg1="%st(0)" And arg2[..3]="%st" op=op[..4]+"p"
+                                       End Select
+                                       args=arg1+","+arg2
+                               EndIf
+                               Local fpsz
+                               If op And op[0]=Asc("f")
+                                       Select op
+                                       Case ..
+                                       "fild","fist","fistp","ficom","ficomp",..
+                                       "fiadd","fisub","fimul","fidiv","fidivr"
+                                       Default
+                                               fpsz=True
+                                       End Select
+                               EndIf
+                               Select sz
+                               Case 1
+                                       op:+"b"
+                               Case 2
+                                       op:+"w"
+                               Case 4
+                                       If fpsz op:+"s" Else op:+"l"
+                               Case 8
+                                       If fpsz op:+"l" Else op:+"q"
+                               End Select
+                       End Select
+                       If op line=Chr(9)+op+Chr(9)+args Else line=""
+               EndIf
+       EndIf
+       
+       WriteString out,line
+       WriteString out,"~n"
+       
+Wend
+
+in.Close
+
+Catch ex:Object
+
+       WriteStdout "fasm2as failed: "+ex.ToString()+"~n"
+       
+       exit_ -1
+
+End Try
+
+End
+
+Function RegSize( r$ )
+       Select r
+       Case "eax","ebx","ecx","edx","esi","edi","ebp","esp"
+               Return 4
+       End Select
+End Function
+
+Function FixArg( arg$ Var,op$="" )
+
+       If Not arg.EndsWith( "]" )
+               If arg[0]=Asc("_")
+                       If op[0]<>Asc("j") And op<>"call" arg="$"+arg
+               Else If (arg[0]>=48 And arg[0]<=57) Or arg[0]=Asc("-")
+                       arg="$"+arg
+               Else
+                       If arg[..2]="st" arg="st("+arg[2..]+")"
+                       arg="%"+arg
+               EndIf
+               Return 0
+       EndIf
+       
+       Local sz
+       
+       If arg.StartsWith( "[" )
+               arg=arg[1..arg.length-1]
+       Else If arg.StartsWith( "byte [" )
+               arg=arg[6..arg.length-1]
+               sz=1
+       Else If arg.StartsWith( "word [" )
+               arg=arg[6..arg.length-1]
+               sz=2
+       Else If arg.StartsWith( "dword [" )
+               arg=arg[7..arg.length-1]
+               sz=4
+       Else If arg.StartsWith( "qword [" )
+               arg=arg[7..arg.length-1]
+               sz=8
+       Else
+               Throw "Error"
+       EndIf
+       
+       arg=arg.Replace( "+-","-" )
+       arg=arg.Replace( "-","+-" )
+
+       Local base$,index$,scale$,disp$
+       For Local t$=EachIn arg.Split( "+" )
+               If t.Contains("*")
+                       If index Throw "Error"
+                       Local bits$[]=t.Split( "*" )
+                       If bits.length<>2 Throw "Error"
+                       index=bits[0]
+                       scale=bits[1]
+               Else If RegSize( t )
+                       If base
+                               If index Throw "Error"
+                               index=t
+                               scale="1"
+                       Else
+                               base=t
+                       EndIf
+               Else
+                       If disp
+                               disp=(disp+"+"+t).Replace( "+-","-" )
+                       Else
+                               disp=t
+                       EndIf
+               EndIf
+       Next
+
+       If base And index
+               arg=disp+"(%"+base+",%"+index+","+scale+")"
+       Else If base
+               arg=disp+"(%"+base+")"
+       Else If index
+               arg=disp+"(,%"+index+","+scale+")"
+       Else If disp
+               arg=disp
+       Else
+               Throw "Error!"
+       EndIf
+       
+       Return sz
+End Function
diff --git a/src/makedocs/bbdoc.bmx b/src/makedocs/bbdoc.bmx
new file mode 100644 (file)
index 0000000..e0947a4
--- /dev/null
@@ -0,0 +1,202 @@
+
+Strict
+
+Import "parse.bmx"
+
+'still pretty ugly - could probably be done in a few lines with Bah.RegEx!
+
+Type TBBLinkResolver
+
+       Method ResolveLink$( link$ ) Abstract
+
+End Type
+
+Private
+
+'finds a 'span' style tag starting at index i - eg: @bold or @{this is bold}
+'
+'returns bit after tag, fills in b and e with begin and end of range.
+Function FindBBTag$( text$,tag$,i,b Var,e Var )
+       Repeat
+               i=text.Find( tag,i )
+               If i=-1 Return
+               If i=0 Or text[i-1]<=32 Or text[i-1]=Asc(">") Exit
+               i:+tag.length
+       Forever
+       b=i
+       i:+1
+       If i=text.length Return
+       Local t$
+       If text[i]=Asc("{")
+               i:+1
+               While i<text.length And text[i]<>Asc("}")
+                       i:+1
+               Wend
+               t=text[b+2..i]
+               If i<text.length i:+1
+               e=i
+       Else
+               i:+1
+               While i<text.length And (IsIdentChar(text[i]) Or text[i]=Asc("."))
+                       i:+1
+               Wend
+               If text[i-1]=Asc(".") i:-1
+               t=text[b+1..i]          
+               e=i
+       EndIf
+       Return t
+End Function
+
+'does simple html tags, bold, italic etc.      
+Function FormatBBTags( text$ Var,bbTag$,htmlTag$ )
+       Local i
+       Repeat
+               Local b,e
+               Local t$=FindBBTag( text,bbTag,i,b,e )
+               If Not t Return
+               
+               t="<"+htmlTag+">"+t+"</"+htmlTag+">"
+               text=text[..b]+t+text[e..]
+               i=b+t.length
+       Forever
+End Function
+
+Public
+
+Function BBToHtml2$( text$,doc:TBBLinkResolver )
+       Local i
+
+       'newlines
+       text=text.Replace( "\~n","<br>~n" )
+       
+       'paras
+       text=text.Replace( "~n~n","~n<p>~n" )
+
+       'tabs
+       text=text.Replace( "~n~t","~n&nbsp;&nbsp; " )
+       
+       'headings
+       i=0
+       Local hl=1
+       Repeat
+               i=text.Find( "~n+",i )
+               If i=-1 Exit
+               
+               Local i2=text.Find( "~n",i+2 )
+               If i2=-1 Exit
+               
+               Local q$=text[i+2..i2]
+               q="<h"+hl+">"+q+"</h"+hl+">"
+               
+               If hl=1 hl=2
+               
+               text=text[..i]+q+text[i2..]
+               i:+q.length
+       Forever
+       
+       'tables
+       i=0
+       Repeat
+               i=text.Find( "~n[",i )
+               If i=-1 Exit
+               
+               Local i2=text.Find( "~n]",i+2 )
+               If i2=-1 Exit
+               
+               Local q$=text[i+2..i2]
+               
+               If q.Find( " | " )=-1   'list?
+                       q=q.Replace( "~n*","<li>" )
+                       q="<ul>"+q+"</ul>"
+               Else
+                       q=q.Replace( "~n*","</td></tr><tr><td> " )
+                       q=q.Replace( " | ","</td><td>" )
+                       q="~n<table><tr><td>"+q+"</table>~n"
+               EndIf
+               
+               text=text[..i]+q+text[i2+2..]
+               i:+q.length
+       Forever
+       
+       'quotes
+       i=0
+       Repeat
+               i=text.Find( "~n{",i )
+               If i=-1 Exit
+               
+               Local i2=text.Find(  "~n}",i+2 )
+               If i2=-1 Exit
+               
+               Local q$=text[i+2..i2]
+               
+               q="<blockquote>"+q+"</blockquote>"
+               
+               text=text[..i]+q+text[i2+2..]
+               i:+q.length
+       Forever
+       
+       'links
+       i=0
+       Repeat
+               Local b,e
+               Local t$=FindBBTag( text,"#",i,b,e )
+               If Not t Exit
+               
+               t=doc.ResolveLink( t )
+               text=text[..b]+t+Text[e..]
+               i=b+t.length
+       Forever
+       
+       'span tags
+       FormatBBTags text,"@","b"
+
+       FormatBBTags text,"%","i"
+
+       'escapes
+       i=0
+       Repeat
+               i=text.Find( "~~",i )
+               If i=-1 Or i=text.length-1 Exit
+               
+               Local r$=Chr( text[i+1] )
+               Select r
+               Case "<" r="&lt;"
+               Case ">" r="&gt;"
+               End Select
+               
+               text=text[..i]+r+text[i+2..]
+               i:+r.length
+       Forever
+       
+       Return text
+       
+End Function
+
+'bbdoc to html conversion
+Function BBToHtml$( text$,doc:TBBLinkResolver )
+       
+       text=text.Replace( "~r~n","~n" )
+       
+       Local out$,i
+       
+       'preformatted code...
+       Repeat
+               Local i1=text.Find( "~n{{",i )
+               If i1=-1 Exit
+
+               Local i2=text.Find(  "~n}}",i+3 )
+               If i2=-1 Exit
+               
+               out:+BBToHtml2( text[i..i1],doc )
+               
+               out:+"<pre>"+text[i1+3..i2].Trim()+"</pre>"
+               
+               i=i2+3
+       Forever
+       
+       out:+BBToHtml2( text[i..],doc )
+       
+       Return out
+       
+End Function   
+               
diff --git a/src/makedocs/docnode.bmx b/src/makedocs/docnode.bmx
new file mode 100644 (file)
index 0000000..30c5a93
--- /dev/null
@@ -0,0 +1,69 @@
+
+Strict
+
+Import BRL.Map
+
+Type TDocNode
+
+       Field id$                       'eg: BRL.Audio
+       Field path$             'eg: Modules/Audio/Audio"
+       Field kind$             'eg: "Module", "Function", "Type" etc
+       
+       Field proto$            'eg: Function LoadImage(...)
+       Field bbdoc$            'eg: Load an image (shortdesc?)
+       Field returns$  'eg: A new image
+       Field about$            'eg: blah etc blah (longdesc?)
+       Field params:TList      'eg: [x - the x coord, y - the y coord]
+       
+       Field docDir$           'eg: ../mod/brl.mod/max2d.mod/doc
+       Field example$  'eg: LoadImage.bmx (path)
+       
+       Field children:TList=New TList
+       
+       Function ForPath:TDocNode( path$ )
+
+               Return TDocNode( _pathMap.ValueForKey( path ) )
+
+       End Function
+       
+       Function Create:TDocNode( id$,path$,kind$ )
+       
+               Local t:TDocNode=TDocNode( _pathMap.ValueForKey( path ) )
+               
+               If t
+                       If t.kind<>"/" And t.path<>path Throw "ERROR: "+t.kind+" "+kind
+                       If t.path = path Return t
+               Else
+                       t=New TDocNode
+                       _pathMap.Insert path,t
+               EndIf
+
+               t.id=id
+               t.path=path
+               t.kind=kind
+               
+               Local q:TDocNode=t
+               
+               Repeat
+                       If path="/" Exit
+                       path=ExtractDir( path )
+                       Local p:TDocNode=TDocNode( _pathMap.ValueForKey( path ) )
+                       If p
+                               p.children.AddLast q
+                               Exit
+                       EndIf
+                       p=New TDocNode
+                       p.id=StripDir(path)
+                       p.path=path
+                       p.kind="/"
+                       p.children.AddLast q
+                       _pathMap.Insert path,p
+                       q=p
+               Forever
+               
+               Return t
+       End Function
+       
+       Global _pathMap:TMap=New TMap
+
+End Type
diff --git a/src/makedocs/docstyle.bmx b/src/makedocs/docstyle.bmx
new file mode 100644 (file)
index 0000000..76a4fa6
--- /dev/null
@@ -0,0 +1,191 @@
+
+Strict
+
+Import BRL.MaxUtil
+
+Import "bbdoc.bmx"
+
+Import "docnode.bmx"
+
+Global BmxDocDir$=BlitzMaxPath()+"/docs/html"
+
+Global NodeKinds$[]=[ "/","Module","Type" ]
+
+Global LeafKinds$[]=[ "Const","Field","Global","Method","Function","Keyword" ]
+
+Global AllKinds$[]=NodeKinds+LeafKinds
+
+Type TDocStyle Extends TBBLinkResolver
+
+       Field html$
+       Field doc:TDocNode
+       Field children:TMap
+       Field docURL$
+       Field absDocDir$                'where output doc goes
+       Field relRootDir$               'relative path to root doc dir
+       
+       Global commands:TMap=New TMap
+
+       Method NodeIsleaf( node:TDocNode )
+               For Local t$=EachIn LeafKinds
+                       If t=node.kind Return True
+               Next
+       End Method
+       
+       Method FindNode:TDocNode( node:TDocNode,id$ )
+
+               If node.id.ToLower()=id Return node
+
+               If node.path.Tolower().EndsWith( "/"+id ) Return node
+
+               For Local t:TDocNode=EachIn node.children
+                       Local p:TDocNode=FindNode( t,id )
+                       If p Return p
+               Next
+       End Method
+       
+       Method NodeURL$( node:TDocNode )
+               If node.kind="Topic"
+                       Return node.path+".html"
+               Else If NodeIsLeaf( node )
+                       Return ExtractDir( node.path )+"/index.html#"+node.id
+               Else If node.path<>"/"
+                       Return node.path+"/index.html"
+               Else
+                       Return "/index.html"
+               EndIf
+       End Method
+       
+       Method ResolveLink$( link$ )
+               Local id$=link.ToLower()
+
+               Local node:TDocNode=FindNode( doc,id )
+               
+               If Not node 
+                       node=FindNode( TDocNode.ForPath( "/" ),id )
+               EndIf
+               
+               If Not node 
+                       Print "Error: Unable to resolve link '"+link+"'"
+                       Return link
+               EndIf
+
+               Local url$=nodeURL( node )
+               
+               'optimize links...
+               If url.StartsWith( docURL+"#" )
+                       url=url[ docURL.length.. ]
+               Else If url.StartsWith( doc.path+"/" )
+                       url="~q"+url[ doc.path.length+1.. ]+"~q"
+               Else
+                       url="~q"+relRootDir+url+"~q"
+               EndIf
+               Return "<a href="+url+">"+link+"</a>"
+       End Method
+       
+       Method EmitDoc( node:TDocNode )
+               
+               Print "Building: "+node.id
+               
+               html=""
+               doc=node
+               children=New TMap
+               docURL=NodeURL( doc )
+               absDocDir=BmxDocDir+ExtractDir( docURL )
+               relRootDir=""
+
+               Local p$=ExtractDir( docURL )
+               While p<>"/"
+                       If relRootDir relRootDir:+"/"
+                       relRootDir:+".."
+                       p=ExtractDir( p )
+               Wend
+               If Not relRootDir relRootDir="."
+
+               CreateDir absDocDir,True
+               
+               If doc.docDir CopyDir doc.docDir,absDocDir
+
+               If docURL.EndsWith( "/index.html" )
+                       Local intro$=absDocDir+"/index.bbdoc"
+                       If FileType( intro )<>FILETYPE_FILE intro$=absDocDir+"/intro.bbdoc"
+                       If FileType( intro )=FILETYPE_FILE
+                               Local t$=LoadText( intro )
+                               If t.find( "commands.html" )<>-1
+                                       Print "Error: Document contains 'commands.html'"
+                               EndIf
+                               doc.about=t+doc.about
+                       EndIf
+               EndIf
+
+               For Local t:TDocNode=EachIn doc.children
+
+                       Local list:TList=TList( children.ValueForKey( t.kind ) )
+                       If Not list
+                               list=New TList
+                               children.Insert t.kind,list
+                       EndIf
+
+                       list.AddLast t
+                       
+                       'update commands.txt
+                       Select t.kind
+                       Case "Keyword"
+                               commands.Insert t.id+" : "+t.bbdoc,NodeURL( t )
+                       Case "Const","Global","Function","Type" ',"Module"
+                               Local i=t.proto.Find( " " )
+                               If i<>-1 commands.Insert t.proto[i+1..].Trim()+" : "+t.bbdoc,NodeURL( t )
+                       End Select
+               Next
+               
+               EmitHeader
+               
+               For Local t$=EachIn NodeKinds
+                       EmitLinks t
+               Next
+               
+               For Local t$=EachIn LeafKinds
+                       EmitLinks t
+               Next
+               
+               For Local t$=EachIn LeafKinds
+                       EmitDecls t
+               Next
+               
+               EmitFooter
+               
+               html=BBToHtml( html,Self )
+               
+               SaveText html,BmxDocDir+docURL
+
+               For Local t$=EachIn NodeKinds
+                       EmitNodes t
+               Next
+       
+       End Method
+       
+       Method EmitNodes( kind$ )
+               Local list:TList=TList( children.ValueForKey( kind ) )
+               If Not list Return
+               For Local t:TDocNode=EachIn list
+                       EmitDoc t
+               Next
+       End Method
+       
+       Method Emit( t$ )
+               html:+t+"~n"
+       End Method
+       
+       Method ChildList:TList( kind$ )
+               Return TList( children.ValueForKey( kind ) )
+       End Method
+       
+       Method EmitHeader() Abstract
+       
+       Method EmitFooter() Abstract
+       
+       Method EmitLinks( kind$ ) Abstract
+       
+       Method EmitDecls( kind$ ) Abstract
+       
+End Type
diff --git a/src/makedocs/fredborgstyle.bmx b/src/makedocs/fredborgstyle.bmx
new file mode 100644 (file)
index 0000000..8fe86f6
--- /dev/null
@@ -0,0 +1,128 @@
+
+Strict
+
+Import "docstyle.bmx"
+
+Type TFredborgStyle Extends TDocStyle
+
+       Method EmitHeader()
+
+               'emit HTML header       
+               Emit "<html><head><title>"+doc.id+"</title>"
+               Emit "<link rel=stylesheet Type=text/css href=~q"+relRootDir+"/styles/fredborg.css~q>"
+               Emit "</head><body>"
+               
+               'emit title bar
+               Emit "<table width=100% cellspacing=0><tr align=center><td class=small>&nbsp;</td>"
+               Emit "<td class=small width=1%><b>"+doc.id+":</b></td>"
+
+               'emit links to summaries                
+               For Local t$=EachIn allKinds
+                       If t="/" Or Not ChildList( t ) Continue
+
+                       Emit "<td class=small width=1%><a href=#_"+t+" class=small>"+t+"s</a></td>"
+
+               Next
+
+               'emit link to module source
+               If doc.kind="Module"
+                       Local t$=ModuleSource( doc.id.ToLower() ),i=t.Find( "/mod/" )
+                       If i<>-1
+                               t=relRootDir+"/../.."+t[i..]
+                               Emit "<td class=small width=1%><a href='"+t+"' class=small>Source</a></td>"
+                       EndIf
+               EndIf
+               
+               'end title bar
+               Emit "<td class=small>&nbsp;</td></tr></table><br><br>"
+               
+               'emit about
+               If doc.about Emit doc.about+"<br><br>"
+
+       End Method
+       
+       Method EmitFooter()
+
+               'emit HTML footer
+               Emit "</body></html>"
+
+       End Method
+       
+       Method EmitLinks( kind$ )
+
+               Local list:TList=ChildList( kind )
+               If Not list Return
+               
+               'emit anchor: _Const, _Function etc...
+               
+               If kind="/"
+               
+                       Emit "<table class=doc cellspacing=3>"
+                       
+                       For Local t:TDocNode=EachIn list
+                       
+                               Emit "<tr><td class=docleft width=1%> #{"+t.id+"}</td></tr>"
+       
+                       Next
+       
+                       Emit "</table>"
+               
+               Else
+               
+                       Emit "<a name=_"+kind+"></a>"
+                       Emit "<h2>"+kind+"s</h2>"
+               
+                       Emit "<table class=doc width=100% cellspacing=3>"
+                       
+                       For Local t:TDocNode=EachIn list
+                       
+                               Emit "<tr><td class=docleft width=1%> #{"+t.id+"}</td><td class=docright>"+t.bbdoc+"</td></tr>"
+       
+                       Next
+       
+                       Emit "</table>"
+               EndIf
+       
+       End Method
+       
+       Method EmitDecls( kind$ )
+
+               Local list:TList=ChildList( kind )
+               If Not list Return
+               
+               Emit "<h2>"+kind+" reference</h2>"
+               
+               For Local t:TDocNode=EachIn list
+               
+                       Emit "<a name=~q"+t.id+"~q></a>"
+               
+                       Emit "<p><table class=doc width=100% cellspacing=3>"
+                       Emit "<tr><td class=doctop colspan=2>"+t.proto+"</td></tr>"
+
+                       If t.returns
+                               Emit "<tr><td class=docleft width=1%>Returns</td><td class=docright>"+t.returns+"</td></tr>"
+                       EndIf
+
+                       If t.bbdoc
+                               Emit "<tr><td class=docleft width=1%>Description</td><td class=docright>"+t.bbdoc+"</td></tr>"
+                       EndIf
+
+                       If t.about
+                               Emit "<tr><td class=docleft width=1%>Information</td><td class=docright>"+t.about+"</td></tr>"
+                       EndIf
+                       
+                       If t.example 
+                               Local p$=t.example
+                               Local link$="<a href=~q"+p+"~q>Example</a>"
+                               Local code$=LoadText( absDocDir+"/"+p ).Trim()
+                               code="~n{{~n"+code+"~n}}~n"
+                               Emit "<tr><td class=docleft width=1%>"+link+"</td><td class=docright>"+code+"</td></tr>"
+                       EndIf
+       
+                       Emit "</table>"
+               
+               Next
+               
+       End Method
+
+End Type
diff --git a/src/makedocs/makedocs.bmx b/src/makedocs/makedocs.bmx
new file mode 100644 (file)
index 0000000..81a2a10
--- /dev/null
@@ -0,0 +1,286 @@
+
+Rem
+
+Build new style docs.
+
+Only builds official docs and brl, maxgui and pub modules.
+
+Calls 'docmods' first, which builds 3rd party modules.
+
+End Rem
+
+Strict
+
+Framework BRL.Basic
+
+Import "docnode.bmx"
+
+Import "fredborgstyle.bmx"
+
+system_ "~q"+BlitzMaxPath()+"/bin/docmods~q"
+
+Local style:TDocStyle=New TFredborgStyle
+
+DeleteDir BmxDocDir,True
+
+CopyDir BlitzMaxPath()+"/docs/src",BmxDocDir
+
+Local root:TDocNode=TDocNode.Create( "BlitzMax Help","/","/" )
+root.about=LoadText( BmxDocDir+"/index.html" )
+
+DocMods
+
+DocBBDocs "/"
+
+style.EmitDoc TDocNode.ForPath( "/" )
+
+Local t$
+For Local kv:TKeyValue=EachIn TDocStyle.commands
+       t:+String( kv.Key() )+"|/docs/html"+String( kv.Value() )+"~n"
+Next
+
+Local p$=BlitzMaxPath()+"/doc/bmxmods/commands.txt"
+If FileType( p )=FILETYPE_FILE t:+LoadText( p )
+
+SaveText t,BmxDocDir+"/Modules/commands.txt"
+
+Cleanup BmxDocDir
+
+'*****
+
+Function Cleanup( dir$ )
+       For Local e$=EachIn LoadDir( dir )
+               Local p$=dir+"/"+e
+               Select FileType( p )
+               Case FILETYPE_DIR
+                       Cleanup p
+               Case FILETYPE_FILE
+                       If ExtractExt( e )="bbdoc"
+                               DeleteFile p
+                       Else If e.ToLower()="commands.html"
+                               DeleteFile p
+                       EndIf
+               End Select
+       Next
+End Function
+
+Function DocMods()
+
+       For Local modid$=EachIn EnumModules()
+
+               If Not modid.StartsWith( "brl." ) And Not modid.StartsWith( "pub." ) And Not modid.StartsWith("maxgui.") Continue
+
+               Local p$=ModuleSource( modid )
+               Try
+                       docBmxFile p,""
+               Catch ex$
+                       Print "Error:"+ex
+               End Try
+       Next
+
+End Function
+
+Function DocBBDocs( docPath$ )
+
+       Local p$=BmxDocDir+docPath
+       
+       For Local e$=EachIn LoadDir( p )
+
+               Local q$=p+"/"+e
+
+               Select FileType( q )
+               Case FILETYPE_FILE
+                       Select ExtractExt( e )
+                       Case "bbdoc"
+                               Local id$=StripExt( e )
+                               If id="index" Or id="intro" Continue
+                               
+                               Local path$=(docPath+"/"+id).Replace( "//","/" )
+                               Local node:TDocNode=TDocNode.Create( id,path,"/" )
+                               
+                               node.about=LoadText( q )
+                       End Select
+               Case FILETYPE_DIR
+                       DocBBDocs docPath+"/"+e
+               End Select
+       Next
+       
+End Function
+
+Function docBmxFile( filePath$,docPath$ )
+
+       If FileType( filePath )<>FILETYPE_FILE
+               Print "Error: Unable to open '"+filePath+"'"
+               Return
+       EndIf
+
+       Local docDir$=ExtractDir( filePath )+"/doc"
+       If FileType( docDir )<>FILETYPE_DIR docDir=""
+
+       Local inrem,typePath$,section$
+       
+       Local bbdoc$,returns$,about$,keyword$,params:TList
+       
+       Local text$=LoadText( filepath )
+       
+       For Local line$=EachIn text.Split( "~n" )
+
+               line=line.Trim()
+               Local tline$=line.ToLower()
+               
+               Local i
+               Local id$=ParseIdent( tline,i )
+               
+               If id="end" id:+ParseIdent( tline,i )
+               
+               If i<tline.length And tline[i]=Asc(":")
+                       id:+":"
+                       i:+1
+               EndIf
+               
+               If inrem
+               
+                       If id="endrem"
+                       
+                               inrem=False
+                               
+                       Else If id="bbdoc:"
+                       
+                               bbdoc=line[i..].Trim()
+                               keyword=""
+                               returns=""
+                               about=""
+                               params=Null
+                               section="bbdoc"
+
+                       Else If bbdoc 
+                       
+                               Select id
+                               Case "keyword:"
+                                       keyword=line[i..].Trim()
+                                       section="keyword"
+                               Case "returns:"
+                                       returns=line[i..].Trim()+"~n"
+                                       section="returns"
+                               Case "about:"
+                                       about=line[i..].Trim()+"~n"
+                                       section="about"
+                               Case "param:"
+                                       If Not params params=New TList
+                                       params.AddLast line[6..].Trim()
+                                       section="param"
+                               Default
+                                       Select section
+                                       Case "about"
+                                               about:+line+"~n"
+                                       Case "returns"
+                                               returns:+" "+line
+                                       Case "param"
+                                               params.AddLast String( params.RemoveLast() )+" "+line
+                                       Default
+                                               'remaining sections 1 line only...
+                                               If line Print "Error: Illegal bbdoc section in '"+filePath+"'"
+                                       End Select
+                               End Select
+                       
+                       EndIf
+               
+               Else If id="rem"
+               
+                       bbdoc=""
+                       inrem=True
+                       
+               Else If id="endtype"
+
+                       If typePath
+                               docPath=typePath
+                               typePath=""
+                       EndIf
+                       
+               Else If id="import" Or id="include"
+               
+                       Local p$=ExtractDir( filePath )+"/"+ParseString( line,i )
+                       
+                       If ExtractExt( p ).ToLower()="bmx"
+                               docBmxFile p,docPath
+                       EndIf
+               
+               Else If bbdoc
+               
+                       Local kind$,proto$
+                       
+                       If keyword
+                               id=keyword
+                               kind="Keyword"
+                               If id.StartsWith( "~q" ) And id.EndsWith( "~q" )
+                                       id=id[1..id.length-1]
+                               EndIf
+                               proto=id
+                       Else If id
+                               For Local t$=EachIn AllKinds
+                                       If id<>t.ToLower() Continue
+                                       kind=t
+                                       proto=line
+                                       id=ParseIdent( line,i )
+                                       Exit
+                               Next
+                       EndIf
+                       
+                       If kind
+
+                               Local path$
+
+                               Select kind
+                               Case "Type"
+                                       If Not docPath Throw "No doc path"
+                                       If typePath Throw "Type path already set"
+                                       typePath=docPath
+                                       docPath:+"/"+id
+                                       path=docPath
+                               Case "Module"
+                                       If docPath Throw "Doc path already set"
+                                       If bbdoc.FindLast( "/" )=-1
+                                               bbdoc="Other/"+bbdoc
+                                       EndIf
+                                       docPath="/Modules/"+bbdoc
+                                       path=docPath
+                                       Local i=bbdoc.FindLast( "/" )
+                                       bbdoc=bbdoc[i+1..]
+                               Default
+                                       If Not docPath Throw "No doc path"
+                                       path=docPath+"/"+id
+                               End Select
+                               
+                               Local i=proto.Find( ")=" )
+                               If i<>-1 
+                                       proto=proto[..i+1]
+                                       If id.StartsWith( "Sort" ) proto:+" )"  'lazy!!!!!
+                               EndIf
+                               i=proto.Find( "=New" )
+                               If i<>-1
+                                       proto=proto[..i]
+                               EndIf
+                               
+                               Local node:TDocNode=TDocNode.Create( id,path,kind )
+                               
+                               node.proto=proto
+                               node.bbdoc=bbdoc
+                               node.returns=returns
+                               node.about=about
+                               node.params=params
+                               
+                               If kind="Module" node.docDir=docDir
+                               
+                               Local tmpExampleFilePath$ = CasedFileName(docDir+"/"+id+".bmx")
+                               If docDir And FileType( tmpExampleFilePath )=FILETYPE_FILE
+                                       node.example=StripDir(tmpExampleFilePath)
+                               EndIf
+                               
+                       EndIf
+                       
+                       bbdoc=""
+
+               EndIf
+       Next
+       
+End Function
diff --git a/src/makedocs/parse.bmx b/src/makedocs/parse.bmx
new file mode 100644 (file)
index 0000000..e76f500
--- /dev/null
@@ -0,0 +1,61 @@
+
+Strict
+
+Function IsAlphaChar( char )
+       Return (char>=Asc("A") And char<=Asc("Z")) Or (char>=Asc("a") And char<=Asc("z")) Or (char=Asc("_"))
+End Function
+
+Function IsDecChar( char )
+       Return (char>=Asc("0") And char<=Asc("9"))
+End Function
+
+Function IsIdentChar( char )
+       Return IsAlphaChar( char ) Or IsDecChar( char )
+End Function
+
+Function IsHexChar( char )
+       Return IsDecChar( char ) Or (char>=Asc("A") And char<=Asc("F")) Or (char>=Asc("a") And char<=Asc("f"))
+End Function
+
+Function IsBinChar( char )
+       Return (char>=Asc("0") And char<=Asc("1"))
+End Function
+
+Function IsPunctChar( char )
+       Select char
+       Case Asc("."),Asc(","),Asc(";"),Asc(":" ),Asc("!"),Asc("?") Return True
+       End Select
+End Function
+
+Function ParseWS$( t$,i Var )
+       Local i0=i
+       While i<t.length And t[i]<=32
+               i:+1
+       Wend
+       Return t[i0..i]
+End Function
+
+Function ParseIdent$( t$,i Var )
+       ParseWS t,i
+       Local i0=i
+       If i<t.length And IsAlphaChar( t[i] )
+               i:+1
+               While i<t.length And (IsIdentChar( t[i] ) Or t[i]=Asc("."))
+                       i:+1
+               Wend
+       EndIf
+       Return t[i0..i]
+End Function
+
+Function ParseString$( t$,i Var )
+       ParseWS t,i
+       If i=t.length Or t[i]<>Asc("~q") Return
+       i:+1
+       Local i0=i
+       While i<t.length And t[i]<>Asc("~q" )
+               i:+1
+       Wend
+       Local q$=t[i0..i]
+       If i<t.length i:+1
+       Return q
+End Function
diff --git a/src/makedocs/readme.txt b/src/makedocs/readme.txt
new file mode 100644 (file)
index 0000000..ebd64c3
--- /dev/null
@@ -0,0 +1,144 @@
+
+docmods has been driving me nuts for a while now, so here's a rewrite...
+
+
+***** makedocs *****
+
+New version of docmods is called makedocs.
+
+New doc system should coexist peacefully with current system as it uses '/docs'
+(plural!) dir as opposed to current '/doc' (singular!) dir.
+
+New doc system depends on some IDE tweaks, so old IDE's can stick with docmods and '/doc'
+dir if they want.
+
+
+***** The docs/html dir *****
+
+All docs now end up in /docs/html. commands.txt ends up in /docs/html/Modules dir.
+/docs/html is deleted and rebuilt from scratch every time makedocs is run.
+
+Generated docs are completely standalone - no more linking into /mod dir etc. This
+means docs can be viewed entirely separately from bmx install.
+
+This does mean some duplication - eg: the examples and images etc found in module 'doc' dirs
+ended up duped. However, this does offer a different solution to the 'oops I stuffed the 
+example code' problem as opposed to the current 'prefix the file with dot' solution...
+
+IDE help tree is now based entirely on contents of /docs/html. Basic idea here is:
+
+* Every folder in /docs/html containing an index.html file is considered to be a node
+in the help tree.
+
+* index.html files are also scanned for local links (eg: href=#blah). These are added to
+the help tree as leaves. Local links starting with non-alpha chars are ignored (TODO).
+
+* html files within a node are also added as leaves. Ditto, html files starting with 
+non-alpha chars are ignored (TODO).
+
+
+***** The docs/src dir *****
+
+Prior to building docs, /docs/src is copied to /docs/html.
+
+This is where static docs go: language guide, user guide, tutorials etc.
+
+By providing a dir tree in /docs/src with appropriate index.html files, the IDE
+can auto integrate custom/static docs into help tree.
+
+/docs/src can also contain .bbdoc files - these are converted to html files by makedocs.
+
+
+***** Doccing modules *****
+
+The basic idea behind docing modules remains the same.
+
+The bbdoc for module declarations now allowed you to provide a 'path' for the module, eg:
+
+Rem
+bbdoc: Audio/Audio Samples
+End Rem
+Module BRL.AudioSample
+
+...this wil cause the module docs to end up in /docs/html/Audio/Audio Samples/index.html.
+
+This actually allows for creative doc arrangments - eg: instead of flat 2 level docs...
+
+Graphics
+       Max2D
+               GLMax2D
+               DX7Max2D
+       Pixmaps
+               BMPLoader
+               PNGLoader
+GUI
+       MaxGUI
+               Win32MaxGui
+               CocoaMaxGUI
+
+...etc...
+
+However, I'm not sure whether that would introduce more confusion than benefit! Thoughts?
+
+
+***** BBDOC system ******
+
+BBDoc is a simple tag based formatting system.
+
+The main benefit it offers is sane link creation - just #Blah to link to Blah without
+worrying about where it is.
+
+To link to consts, globals, functions etc, use eg: #LoadImage.
+
+To link to modules, use eg: #BRL.Audio.
+
+BBDoc supports 2 kinds of tags - span tags and div tags.
+
+Span tags may appear anywhere, but must be preceded by a space. The tag affects the
+succeeding identifier (identifiers include _ and .). Span tags may be followed by {} to
+enclose text containing spaces, non-identifier characters etc.
+
+Div tags must appear at the start of a line. Div tags affect one or more lines.
+
+Span tags:
+
+# link
+@ bold
+% italic
+
+Div tags:
+
+. tab - remainder of line is indented
++ heading - remainder of line is a heading
+[ start table
+* start table row (only within tables)
+] end table
+{{ start preformatted block
+}} end preformatted block (this is the only tag recognized within a preformatted block)
+
+Misc tags:
+
+\~n line break.
+| start table cell (only within tables) - must have a space on either side.
+
+BBDoc also converts double newline sequences into paragraph breaks.
+
+Literal tag chars can be inserted using '~'. To insert a '~', use '~~'.
+
+***** Examples *****
+
+This is in bold. %{But this lot} is in italics.
+
+This is ~#not a link!
+
+Please refer to the #{User Guide} for more information.
+
+Here is a table:
+[ @Item | @Value
+* item1 | value1
+]
+
+{{
+This is some sample code.
+}}
diff --git a/src/maxide/Info.plist b/src/maxide/Info.plist
new file mode 100644 (file)
index 0000000..6f18dcf
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDocumentTypes</key>
+       <array>
+               <dict>
+                       <key>CFBundleTypeExtensions</key>
+                       <array>
+                       <string>bmx</string>
+                       </array>
+                       <key>CFBundleTypeIconFile</key>
+                       <string>MaxIDE.icns</string>
+                       <key>CFBundleTypeRole</key>
+                       <string>Editor</string>
+                       <key>LSIsAppleDefaultForType</key>
+                       <true/>
+               </dict>
+       </array>
+       <key>CFBundleExecutable</key>
+       <string>MaxIDE</string>
+       <key>CFBundleIconFile</key>
+       <string>MaxIDE.icns</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+</dict>
+</plist>
diff --git a/src/maxide/bmxlogo.png b/src/maxide/bmxlogo.png
new file mode 100644 (file)
index 0000000..16dcc44
Binary files /dev/null and b/src/maxide/bmxlogo.png differ
diff --git a/src/maxide/default.language.ini b/src/maxide/default.language.ini
new file mode 100644 (file)
index 0000000..d521702
--- /dev/null
@@ -0,0 +1,307 @@
+[LanguageDefinition]
+
+LanguageID = English (English)
+LanguageVersion = v1.07
+LanguageAuthor = BRL
+
+; Toolbar Tips
+tb_new                                       = "New"
+tb_open                                      = "Open"
+tb_close                                     = "Close"
+tb_save                                      = "Save"
+tb_cut                                       = "Cut"
+tb_copy                                      = "Copy"
+tb_paste                                     = "Paste"
+tb_find                                      = "Find"
+tb_build                                     = "Build"
+tb_buildrun                                  = "Build and Run"
+tb_step                                      = "Step"
+tb_stepin                                    = "Step In"
+tb_stepout                                   = "Step Out"
+tb_stop                                      = "Stop"
+tb_home                                      = "Home"
+tb_back                                      = "Back"
+tb_forward                                   = "Forward"
+tb_continue                                  = "Continue"
+
+; Tabs
+tab_help                                     = "Help"
+tab_output                                   = "Output"
+tab_locked:%1                                = "build:%1"
+
+; Navbar Tabs
+navtab_home                                  = "Home"
+navtab_code                                  = "Code"
+navtab_debug                                 = "Debug"
+
+; Navigation Tree Nodes
+navnode_help                                 = "Help"
+navnode_projects                             = "Projects"
+navnode_addproject                           = "Add Project"
+navnode_moduleindex                          = "Index"
+navnode_thirdpartymods                       = "Third party modules"
+
+; Misc Buttons
+btn_ok                                       = "OK"
+btn_cancel                                   = "Cancel"
+btn_close                                    = "Close"
+
+; Find Requester
+find_window_title                            = "Find"
+find_label_find                              = "Find"
+find_btn_find                                = "Find"
+find_notification_cannotfind                 = "Could not find '%1'."
+
+; Find & Replace Requester
+replace_window_title                         = "Find and Replace"
+replace_label_find                           = "Find"
+replace_label_replacewith                    = "Replace With"
+replace_btn_replace                          = "Replace"
+replace_btn_replaceall                       = "Replace All"
+replace_btn_findnext                         = "Find Next"
+
+; About Requester
+about_window_title                           = "About MaxIDE"
+about_label_bccver                           = "BCC Version"
+about_label_bmxpath                          = "BlitzMax Path"
+about_label_mingwpath                        = "MinGW Path"
+about_label_fasmver                          = "FASM Version"
+about_label_gccver                           = "GCC Version"
+about_label_gplusplusver                     = "G++ Version"
+about_error_unavailable                      = "Unavailable"
+about_error_notapplicable                    = "n/a"
+
+; Goto Requester
+goto_window_title                            = "Goto Line"
+goto_label_linenum                           = "Line Number"
+goto_btn_goto                                = "Goto"
+
+; Command Line Requester
+cmdline_window_title                         = "Program Command Line"
+cmdline_label_cmdline                        = "Program command line"
+
+; Progress Requester
+progress_window_title                        = "Progress Requester"
+
+; Options Requester
+options_window_title                         = "Options"
+options_optionstab                           = "Options"
+options_editortab                            = "Editor"
+options_toolstab                             = "Tools"
+
+options_options_label_language               = "Language"
+options_options_btn_showtoolbar              = "Show Toolbar"
+options_options_btn_autorestore              = "Open Files at Startup"
+options_options_btn_autocaps                 = "Auto Capitalize"
+options_options_btn_syntaxhighlight          = "Syntax Highlighting"
+options_options_btn_bracketmatching          = "Enable .bmx Bracket Matching"
+options_options_btn_autobackup               = "Auto Backup"
+options_options_btn_autoindent               = "Auto Indent"
+options_options_btn_autohideoutput           = "Hide Output When Process Completes"
+options_options_btn_useexternalbrowser       = "Use External Help Browser"
+options_options_btn_osshortcuts              = "Use OS Specific Shortcut Keys"
+options_options_btn_sortcodeviewnodes        = "Sort Nodes in Code View"
+
+options_editor_label_background              = "Background"
+options_editor_itemlabel_tabsize             = "Tab Size:"
+options_editor_label_plaintext               = "Plain Text"
+options_editor_label_remarks                 = "Remarks"
+options_editor_label_strings                 = "Strings"
+options_editor_label_keywords                = "Keywords"
+options_editor_label_numbers                 = "Numbers"
+options_editor_label_matchings               = "Matchings"
+
+options_tools_label_output                   = "Output"
+options_tools_label_navbar                   = "Navbar"
+
+options_font_desc_user                       = "User Defined Font"
+options_font_desc_guidefault                 = "GUI Default Font"
+options_font_desc_monospaced                 = "Monospaced Font"
+options_font_desc_sansserif                  = "Sans Serif Font"
+options_font_desc_serif                      = "Serif Font"
+options_font_desc_script                     = "Script Font"
+
+; Text Style Control
+txtstyle_underline                           = "Underline"
+txtstyle_normal                              = "Normal"
+txtstyle_bold                                = "Bold"
+txtstyle_italic                              = "Italic"
+txtstyle_bolditalic                          = "Bold + Italic"
+
+; Project Manager
+projman_window_title                         = "Project Manager"
+projman_btn_addproj                          = "Add Project"
+projman_btn_delproj                          = "Remove Project"
+projman_btn_moveup                           = "Move Up"
+projman_btn_movedn                           = "Move Down"
+projman_btn_properties                       = "Properties"
+
+; Project Requester
+project_window_title                         = "Project Properties"
+project_group_details                        = "Project Details"
+project_label_name                           = "Name"
+project_defaultname                          = "New Project"
+project_label_path                           = "Path"
+project_group_svn                            = "Subversion Control"
+project_label_url                            = "URL"
+project_label_username                       = "Username"
+project_label_password                       = "Password"
+project_btn_checkout                         = "Check Out Project"
+project_btn_update                           = "Update Project"
+project_btn_commit                           = "Commit Project"
+project_requestfolder_title                  = "Select the project folder"
+
+; Syncmods Requester
+syncmods_window_title                        = "Synchronize Modules"
+syncmods_label_username                      = "Username"
+syncmods_label_password                      = "Password"
+syncmods_label_proxyserver                   = "Proxy Server"
+syncmods_process_label                       = "Synchronize Modules"
+syncmods_btn_sync                            = "Sync"
+
+; Search Requester
+search_window_title                          = "Find In Files"
+search_label_find                            = "Find"
+search_label_filetypes                       = "File Types"
+search_type_bmaxfiles                        = "BlitzMax Files"
+search_type_codefiles                        = "Code Files"
+search_type_allfiles                         = "All Files (Warning: Includes Binary Files)"
+search_label_searchpath                      = "Search Path"
+search_btn_searchsubfolders                  = "Search sub-directories"
+search_btn_startsearch                       = "Search"
+search_btn_stopsearch                        = "Stop Search"
+search_requestfolder_title                   = "Choose a folder to search..."
+search_msg_complete                          = "Search complete! Found %1 instance(s)!"
+search_msg_searchingdir                      = "Searching: %1"
+search_error_pathnotfound                    = "The specified path does not exist!"
+search_error_pathisfile                      = "The path entered is for a file, please enter the path of a directory."
+search_error_nosearchstring                  = "You must enter a search string to find!"
+search_safetynotification                    = "There have been %1 instances found.\n\nWould you like to continue?"
+
+; Misc Notifications / Requesters
+request_restart                              = "MaxIDE would like to restart."
+request_closeall                             = "MaxIDE needs to close all documents before continuing."
+request_openfile                             = "Open File"
+request_saveas_title                         = "Save As"
+request_importbb_title                       = "Import .bb file"
+request_savechanges                          = "Save changes to %1?"
+notify_demo_featureunavailable               = "This feature is unavailable in the demo version of BlitzMax."
+
+; SVN Messages
+svn_notification_nodehostnotfound            = "Node host not found."
+svn_notification_nodeprojectnotfound         = "Node project not found."
+svn_msg_updating                             = "Updating %1"
+svn_msg_committing                           = "Committing %1"
+svn_msg_checkingout                          = "Checking out %1 to %2"
+
+; Output Messages
+output_error_compileerror                    = "Compile Error\n\n%1"
+output_notification_stillbusy                = "Current process still busy %1."
+output_notification_processfailure           = "Process failure with %1."
+output_notification_processfailure           = "Process failed to start %1."
+output_msg_rebuildingdocs                    = "Rebuilding documentation..."
+output_msg_buildingmods                      = "Building Modules"
+output_msg_converting                         = "Converting %1"
+output_msg_processcomplete                   = "Process complete"
+output_msg_processterminated                 = "Process terminated"
+output_msg_debugfailure                      = "Process debug failure. Cannot write:\n%1"
+
+; Loading Errors
+loaderror_failed                             = "Failed to open '%1'."
+loaderror_docsnotfound                       = "Documentation not found.\n\nWould you like to rebuild documentation now?"
+
+; Misc
+status_line_char                             = "Line: %1 Char: %2"
+msg_loading                                  = "Loading %1"
+msg_highlightingcode                         = "Highlighting Code"
+
+; Menus
+menu_file                                    = "&File"
+menu_file_new                                = "&New"
+menu_file_open                               = "&Open..."
+menu_file_open_recent                        = "Open &Recent"
+menu_file_closetab                           = "&Close Tab"
+menu_file_closealltabs                       = "Close All Tabs"
+menu_file_closeothertabs                     = "Close Other Tabs"
+menu_file_save                               = "&Save"
+menu_file_saveas                             = "Save &As"
+menu_file_saveall                            = "Save A&ll"
+menu_file_nexttab                            = "&Next Tab"
+menu_file_prevtab                            = "&Previous Tab"
+menu_file_importbb                           = "Import BB Project..."
+menu_file_ideoptions                         = "IDE Options"
+menu_file_projectmanager                     = "&Project Manager"
+menu_file_print                              = "Print"
+menu_file_exit                               = "Exit"
+
+menu_edit                                    = "&Edit"
+menu_edit_undo                               = "&Undo"
+menu_edit_redo                               = "&Redo"
+menu_edit_cut                                = "Cu&t"
+menu_edit_copy                               = "&Copy"
+menu_edit_paste                              = "&Paste"
+menu_edit_selectall                          = "Select &All"
+menu_edit_blockindent                        = "Block Indent"
+menu_edit_blockoutdent                       = "Block Outdent"
+menu_edit_find                               = "&Find..."
+menu_edit_findnext                           = "Find Next"
+menu_edit_replace                            = "&Replace..."
+menu_edit_gotoline                           = "&Goto Line..."
+menu_edit_findinfiles                        = "Find in F&iles"
+
+menu_program                                 = "&Program"
+menu_program_build                           = "&Build"
+menu_program_buildandrun                     = "Build and &Run"
+menu_program_commandline                     = "Command &Line"
+menu_program_step                            = "&Step"
+menu_program_stepin                          = "Step &In"
+menu_program_stepout                         = "Step &Out"
+menu_program_terminate                       = "&Terminate"
+menu_program_buildoptions                    = "Build Options"
+menu_program_buildoptions_quick              = "Quick Build"
+menu_program_buildoptions_debug              = "Debug Build"
+menu_program_buildoptions_threaded           = "Threaded Build"
+menu_program_buildoptions_guiapp             = "Build GUI App"
+menu_program_lockbuildfile                   = "&Lock Build File"
+menu_program_unlockbuildfile                 = "&Unlock Build File"
+menu_program_syncmods                        = "Synchronize Modules..."
+menu_program_buildmods                       = "Build &Modules"
+menu_program_rebuildallmods                  = "Rebuild &All Modules"
+menu_program_rebuilddocs                     = "&Rebuild Documentation"
+
+menu_help                                    = "&Help"
+menu_help_home                               = "&Home"
+menu_help_back                               = "&Back"
+menu_help_forward                            = "&Forward"
+menu_help_quickhelp                          = "&Quick Help"
+menu_help_aboutmaxide                        = "&About MaxIDE"
+
+; Popup Menus
+popup_edit                                   = "Edit"
+popup_edit_quickhelp                         = "Quick Help"
+popup_edit_cut                               = "Cut"
+popup_edit_copy                              = "Copy"
+popup_edit_paste                             = "Paste"
+popup_edit_selectall                         = "Select All"
+popup_edit_blockindent                       = "Block Indent"
+popup_edit_blockoutdent                      = "Block Outdent"
+popup_edit_find                              = "Find"
+popup_edit_findnext                          = "Find Next"
+popup_edit_replace                           = "Replace"
+popup_edit_goto                              = "Goto Line"
+
+popup_output                                 = "Edit"
+popup_output_cut                             = "Cut"
+popup_output_copy                            = "Copy"
+popup_output_paste                           = "Paste"
+popup_output_stop                            = "Stop"
+
+popup_nav_proj                               = "Proj"
+popup_nav_proj_refresh                       = "Refresh"
+popup_nav_proj_clean                         = "Clean"
+popup_nav_proj_findinfiles                   = "Find in Files"
+popup_nav_proj_explore                       = "Explore"
+popup_nav_proj_shell                         = "Shell"
+popup_nav_proj_svnupdate                     = "Update Version"
+popup_nav_proj_svncommit                     = "Commit Version"
+popup_nav_proj_properties                    = "Properties"
\ No newline at end of file
diff --git a/src/maxide/makeicons/Back.png b/src/maxide/makeicons/Back.png
new file mode 100644 (file)
index 0000000..c70a451
Binary files /dev/null and b/src/maxide/makeicons/Back.png differ
diff --git a/src/maxide/makeicons/Build-Run.png b/src/maxide/makeicons/Build-Run.png
new file mode 100644 (file)
index 0000000..f03f3ef
Binary files /dev/null and b/src/maxide/makeicons/Build-Run.png differ
diff --git a/src/maxide/makeicons/Build.png b/src/maxide/makeicons/Build.png
new file mode 100644 (file)
index 0000000..f9b8d2f
Binary files /dev/null and b/src/maxide/makeicons/Build.png differ
diff --git a/src/maxide/makeicons/Close.png b/src/maxide/makeicons/Close.png
new file mode 100644 (file)
index 0000000..4755807
Binary files /dev/null and b/src/maxide/makeicons/Close.png differ
diff --git a/src/maxide/makeicons/Copy.png b/src/maxide/makeicons/Copy.png
new file mode 100644 (file)
index 0000000..8d7751b
Binary files /dev/null and b/src/maxide/makeicons/Copy.png differ
diff --git a/src/maxide/makeicons/Cut.png b/src/maxide/makeicons/Cut.png
new file mode 100644 (file)
index 0000000..8e41a70
Binary files /dev/null and b/src/maxide/makeicons/Cut.png differ
diff --git a/src/maxide/makeicons/Find.png b/src/maxide/makeicons/Find.png
new file mode 100644 (file)
index 0000000..ca4b46f
Binary files /dev/null and b/src/maxide/makeicons/Find.png differ
diff --git a/src/maxide/makeicons/Forward.png b/src/maxide/makeicons/Forward.png
new file mode 100644 (file)
index 0000000..8a53374
Binary files /dev/null and b/src/maxide/makeicons/Forward.png differ
diff --git a/src/maxide/makeicons/Go.png b/src/maxide/makeicons/Go.png
new file mode 100644 (file)
index 0000000..5b6b736
Binary files /dev/null and b/src/maxide/makeicons/Go.png differ
diff --git a/src/maxide/makeicons/Home.png b/src/maxide/makeicons/Home.png
new file mode 100644 (file)
index 0000000..7a8b526
Binary files /dev/null and b/src/maxide/makeicons/Home.png differ
diff --git a/src/maxide/makeicons/New.png b/src/maxide/makeicons/New.png
new file mode 100644 (file)
index 0000000..61ad414
Binary files /dev/null and b/src/maxide/makeicons/New.png differ
diff --git a/src/maxide/makeicons/Open.png b/src/maxide/makeicons/Open.png
new file mode 100644 (file)
index 0000000..cbb468c
Binary files /dev/null and b/src/maxide/makeicons/Open.png differ
diff --git a/src/maxide/makeicons/Paste.png b/src/maxide/makeicons/Paste.png
new file mode 100644 (file)
index 0000000..56eebd1
Binary files /dev/null and b/src/maxide/makeicons/Paste.png differ
diff --git a/src/maxide/makeicons/Save.png b/src/maxide/makeicons/Save.png
new file mode 100644 (file)
index 0000000..2e45ce2
Binary files /dev/null and b/src/maxide/makeicons/Save.png differ
diff --git a/src/maxide/makeicons/Step-In.png b/src/maxide/makeicons/Step-In.png
new file mode 100644 (file)
index 0000000..d5f8e46
Binary files /dev/null and b/src/maxide/makeicons/Step-In.png differ
diff --git a/src/maxide/makeicons/Step-Out.png b/src/maxide/makeicons/Step-Out.png
new file mode 100644 (file)
index 0000000..87d5c3b
Binary files /dev/null and b/src/maxide/makeicons/Step-Out.png differ
diff --git a/src/maxide/makeicons/Step.png b/src/maxide/makeicons/Step.png
new file mode 100644 (file)
index 0000000..6eae3d0
Binary files /dev/null and b/src/maxide/makeicons/Step.png differ
diff --git a/src/maxide/makeicons/Stop.png b/src/maxide/makeicons/Stop.png
new file mode 100644 (file)
index 0000000..3f38a83
Binary files /dev/null and b/src/maxide/makeicons/Stop.png differ
diff --git a/src/maxide/makeicons/makeicons.bmx b/src/maxide/makeicons/makeicons.bmx
new file mode 100644 (file)
index 0000000..c8b68e8
--- /dev/null
@@ -0,0 +1,62 @@
+
+Strict
+
+Local n
+Repeat
+       Local t$
+       ReadData t$
+       If Not t Exit
+       n:+1
+Forever
+
+Local sz=24
+
+Local p:TPixmap
+
+RestoreData Here
+Local x=0
+
+Repeat
+       Local t$
+       ReadData t
+       If Not t Exit
+       
+       If t<>" "
+               Local q:TPixmap=LoadPixmap( t+".png" )
+               If Not p
+                       Local rgb=0'q.readpixel( 0,0 )
+                       p=TPixmap.Create( n*sz,sz,PF_RGBA8888 )
+                       For Local y=0 Until sz
+                               For Local x=0 Until n*sz
+                                       p.WritePixel x,y,rgb
+                               Next
+                       Next
+               EndIf
+               If q.width>sz Or q.height>sz
+                       q=ResizePixmap( q,sz,sz )
+               EndIf
+               Local cx=(sz-q.width)/2
+               Local cy=(sz-q.height)/2
+               p.paste q,x+cx,cy
+       EndIf
+       x:+sz
+Forever
+
+SavePixmapPNG p,"../toolbar.png"
+
+Local i:TImage=LoadImage(p)
+
+Graphics 640,480,0
+DrawPixmap p,0,0
+
+DrawImage i,0,100
+Flip
+WaitKey
+
+#Here
+DefData "New","Open","Close","Save"," "
+DefData "Cut","Copy","Paste","Find"," "
+DefData "Build","Build-Run","Step","Step-In","Step-Out","Stop"," "
+DefData "Home","Back","Forward"
+DefData "Go",""
+
diff --git a/src/maxide/maxicons.o b/src/maxide/maxicons.o
new file mode 100644 (file)
index 0000000..dc11fcf
Binary files /dev/null and b/src/maxide/maxicons.o differ
diff --git a/src/maxide/maxide.bmx b/src/maxide/maxide.bmx
new file mode 100644 (file)
index 0000000..ebf04df
--- /dev/null
@@ -0,0 +1,6560 @@
+
+' maxide.bmx - blitzmax native integrated development environment
+
+' by simonarmstrong@blitzbasic.com
+
+' released under the Blitz Shared Source Code License 2005
+' released into the public domain 2006
+
+' requires MaxGui modules to run
+
+Strict
+
+Framework MaxGUI.Drivers
+Import MaxGUI.ProxyGadgets
+
+?Win32
+Import "maxicons.o"
+?
+
+'Import bah.gtkmaxgui
+'Import bah.gtkwebgtkhtml
+'Import bah.gtkwebmozilla
+
+Import brl.eventqueue
+Import brl.standardio
+Import brl.filesystem
+Import brl.system
+Import brl.ramstream
+Import pub.freeprocess
+Import brl.pngloader
+Import brl.timer
+Import brl.maxutil
+
+Incbin "bmxlogo.png"
+Incbin "toolbar.png"
+Incbin "splash.png"
+Incbin "default.language.ini"
+
+Const DEFAULT_LANGUAGEPATH$ = "incbin::default.language.ini"
+
+?Linux
+Incbin "window_icon.png"
+?
+
+AppTitle = "MaxIDE"
+
+Const IDE_VERSION$="1.43"
+Const TIMER_FREQUENCY=15
+
+?Win32
+Extern
+       Global _bbusew  'secret 'NT' flag
+End Extern
+
+If Not _bbusew
+       Notify..
+       "This program is not compatible with Windows 95/98/ME.~n~n"+..
+       "Please visit www.blitzbasic.com to download a compatible version.",True
+       End
+EndIf
+?
+
+Global BCC_VERSION$="{unknown}"        'not valid until codeplay opened
+
+Const EOL$="~n"
+
+Const ABOUT$=..
+"{bcc_version} - Copyright Blitz Research Ltd.~n~n"+..
+"Please visit www.blitzbasic.com for all your Blitz related needs!"
+
+Const ABOUTDEMO$=..
+"This demo features both the core BlitzMax package and optional MaxGUI module.~n~n"+..
+"Please note that the MaxGUI module must be purchased separately."
+
+Const FileTypes$="bmx,bbdoc,txt,ini,doc,plist,bb,cpp,c,cc,m,cxx,s,glsl,hlsl,lua,py,h,hpp,html,htm,css,js,bat,mm,as,java,bbx,cx"
+Const FileTypeFilters$="Code Files:"+FileTypes$+";All Files:*"
+
+Const HOMEPAGE$="/docs/html/index.html"
+
+?MacOS
+Global SVNCMD$="/usr/local/bin/svn"
+Const LABELOFFSET=2
+?Win32
+Global SVNCMD$="svn"
+Const LABELOFFSET=4
+?Linux
+Global SVNCMD$="/usr/bin/svn"
+Const LABELOFFSET=0
+?
+
+Const MENUNEW=1
+Const MENUOPEN=2
+Const MENUCLOSE=3
+Const MENUSAVE=4
+Const MENUSAVEAS=5
+Const MENUSAVEALL=6
+Const MENUPRINT=7
+Const MENUQUIT=8
+
+Const MENUUNDO=9
+Const MENUREDO=10
+Const MENUCUT=11
+Const MENUCOPY=12
+Const MENUPASTE=13
+Const MENUSELECTALL=14
+Const MENUGOTO=15
+Const MENUINDENT=16
+Const MENUOUTDENT=17
+Const MENUFIND=18
+Const MENUFINDNEXT=19
+Const MENUREPLACE=20
+Const MENUNEXT=21
+Const MENUPREV=22
+Const MENUBUILD=23
+Const MENURUN=24
+
+Const MENUSTEP=25
+Const MENUSTEPIN=26
+Const MENUSTEPOUT=27
+Const MENUSTOP=28
+
+Const MENULOCKBUILD=29
+Const MENUUNLOCKBUILD=30
+Const MENUBUILDMODULES=31
+Const MENUBUILDALLMODULES=32
+
+Const MENUQUICKENABLED=33
+Const MENUDEBUGENABLED=34
+Const MENUGUIENABLED=35
+
+Const MENUCOMMANDLINE=36
+'Const MENUSYNCMODS=37
+Const MENUIMPORTBB=38
+Const MENUFINDINFILES=39
+Const MENUPROJECTMANAGER=40
+Const MENUSHOWCONSOLE=41
+Const MENUOPTIONS=42
+
+Const MENUHOME=43
+Const MENUBACK=44
+Const MENUFORWARD=45
+Const MENUQUICKHELP=46
+Const MENUABOUT=47
+
+Const MENUNEWVIEW=48
+Const MENUDOCMODS=49
+
+Const MENUTRIGGERDOCMODS=50
+Const MENUTRIGGERSYNCDOCS=51
+
+Const MENUCLOSEALL=53
+
+Const MENUREFRESH=54
+Const MENUBROWSE=55
+Const MENUSHELL=56
+Const MENUPROPS=57
+
+Const MENUUPDATE=58
+Const MENUCOMMIT=59
+
+Const MENUCLOSEOTHERS=60
+
+Const MENUTHREADEDENABLED=61
+
+Const MENURECENT=256
+
+Const TB_NEW=0
+Const TB_OPEN=1
+Const TB_CLOSE=2
+Const TB_SAVE=3
+Const TB_CUT=5
+Const TB_COPY=6
+Const TB_PASTE=7
+Const TB_FIND=8
+Const TB_BUILD=10
+Const TB_BUILDRUN=11
+Const TB_STEP=12
+Const TB_STEPIN=13
+Const TB_STEPOUT=14
+Const TB_STOP=15
+Const TB_HOME=17
+Const TB_BACK=18
+Const TB_FORWARDS=19
+Const TB_CONTINUE=20
+
+Const TAB$=Chr(9)
+Const QUOTES$=Chr(34)
+
+Global TEMPCOUNT
+Global is_demo
+Global codeplay:TCodePlay
+
+Function CheckDemo()
+       If Not is_demo Return 1
+       Notify LocalizeString("{{notify_demo_featureunavailable}}")
+       Return 0
+End Function
+
+Global defaultLanguage:TMaxGUILanguage = LoadLanguage( DEFAULT_LANGUAGEPATH )
+
+SetLocalizationLanguage( defaultLanguage )
+SetLocalizationMode( LOCALIZATION_ON|LOCALIZATION_OVERRIDE )
+
+codeplay=New TCodePlay
+codeplay.Initialize
+
+While codeplay.running
+       codeplay.poll
+Wend
+
+End
+
+Function Quote$(a$)            'add quotes to arg if spaces found
+       Local   p
+       If Not a.length Return
+       If a[0]=34 Return a     'already quoted
+       p=a.find(" ")
+       If p=-1 Return a        'no spaces
+       Return Chr(34)+a+Chr(34)                
+End Function
+
+Type TToken
+       Field token$
+       Field help$
+       Field ref$      
+       Method Create:TToken(t$,h$,r$)
+               token=t
+               help=h
+               ref=r
+               Return Self
+       End Method
+End Type
+
+Type TQuickHelp
+       Field map:TMap=New TMap 'key=lower(token) value=token:TToken
+               
+       Method AddCommand:TQuickHelp(t$,l$,a$)
+               map.Insert t.ToLower(),New TToken.Create(t$,l$,a$)
+       End Method
+       
+       Method Token$(cmd$)
+               Local t:TToken = TToken(map.ValueForKey(cmd.toLower()))
+               If t Return t.token
+       End Method
+       
+       Method Help$(cmd$)
+               Local t:TToken = TToken(map.ValueForKey(cmd.toLower()))
+               If t Return t.help
+       End Method
+       
+       Method Link$(cmd$)
+               Local t:TToken = TToken(map.ValueForKey(cmd.toLower()))
+               If t Return t.ref
+       End Method
+       
+       Function LoadCommandsTxt:TQuickHelp(bmxpath$)
+               Local   text$
+               Local   qh:TQuickHelp
+               Local   i:Int,c,p,q
+               Local   token$,help$,anchor$
+               Try
+                       text=CacheAndLoadText(bmxpath+"/docs/html/Modules/commands.txt")
+               Catch exception:Object
+                       Return Null
+               EndTry
+               If Not text Return Null
+               qh=New TQuickHelp
+               For Local l$ = EachIn text.Split("~n")
+                       For i=0 Until l.length
+                               c=l[i]
+                               If c=Asc("_") Continue
+                               If c>=Asc("0") And c<=Asc("9") Continue
+                               If c>=Asc("a") And c<=Asc("z") Continue
+                               If c>=Asc("A") And c<=Asc("Z") Continue
+                               Exit
+                       Next
+                       token$=l[..i]
+                       help$=""
+                       anchor$=""
+                       q=l.findlast("|")
+                       If q>=0
+                               help=l[..q]
+                               anchor=l[q+1..]
+                       EndIf                   
+                       qh.AddCommand token,help,anchor
+               Next
+               Return qh
+       End Function
+End Type
+
+Const TOOLSHOW=1
+Const TOOLREFRESH=2
+Const TOOLNEW=3
+Const TOOLOPEN=4
+Const TOOLCLOSE=5
+Const TOOLSAVE=6
+Const TOOLHELP=7
+Const TOOLUNDO=8
+Const TOOLREDO=9
+Const TOOLCUT=10
+Const TOOLCOPY=11
+Const TOOLPASTE=12
+Const TOOLQUICKSAVE=13
+Const TOOLSAVEAS=14
+Const TOOLGOTO=15
+Const TOOLFIND=16
+Const TOOLFINDNEXT=17
+Const TOOLREPLACE=18
+Const TOOLBUILD=19
+Const TOOLRUN=20
+Const TOOLLOCK=21
+Const TOOLUNLOCK=22
+Const TOOLSELECT=23
+Const TOOLSELECTALL=24
+Const TOOLINDENT=25
+Const TOOLOUTDENT=26
+Const TOOLACTIVATE=27
+Const TOOLNAVIGATE=28
+Const TOOLNEWVIEW=29
+Const TOOLMENU=30
+Const TOOLPRINT=31
+Const TOOLERROR=32
+Const TOOLOUTPUT=32
+
+Type TTool
+       Method Invoke(command,argument:Object=Null)
+       End Method
+End Type
+
+Type TRequester
+       
+       Const STYLE_OK% = 1, STYLE_CANCEL% = 2
+       Const STYLE_DIVIDER% = 4, STYLE_STATUS% = 8
+       Const STYLE_RESIZABLE% = 16, STYLE_STDBORDER% = 32
+       Const STYLE_MODAL% = 64
+
+       Field   host:TCodePlay
+       Field   window:TGadget,ok:TGadget,cancel:TGadget,divider:TGadget
+       Field   centered, modal
+
+       Method initrequester(owner:TCodeplay,label$,w=260,h=60,flags=STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER,oktext$="{{btn_ok}}")
+               
+               host=owner
+               If (flags&STYLE_MODAL) Then flags:|STYLE_STDBORDER
+               
+               If (flags & (STYLE_CANCEL|STYLE_OK)) Then h:+32;If (flags&STYLE_DIVIDER) Then h:+12
+               
+               Local windowflags% = WINDOW_TITLEBAR|WINDOW_HIDDEN|WINDOW_CLIENTCOORDS
+               If (flags & STYLE_STATUS) Then windowflags:|WINDOW_STATUS
+               If (flags & STYLE_RESIZABLE) Then windowflags:|WINDOW_RESIZABLE
+               If Not (flags & STYLE_STDBORDER) Then windowflags:|WINDOW_TOOL
+               
+               window=CreateWindow(label,0,0,w,h,host.window,windowflags)
+               
+               If (flags & STYLE_RESIZABLE) Then
+                       If (flags & STYLE_STDBORDER) Then SetMaxWindowSize(window,ClientWidth(Desktop()),ClientHeight(Desktop()))
+                       SetMinWindowSize(window,w,h)
+               EndIf
+               
+               If (flags & STYLE_OK) Then
+                       
+                       ok=CreateButton(oktext,ClientWidth(window)-101,ClientHeight(window)-32,95,26,window,BUTTON_OK)
+                       SetGadgetLayout(ok,EDGE_CENTERED,EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED)
+                       
+                       If (flags & STYLE_CANCEL) Then
+                               cancel=CreateButton("{{btn_cancel}}",6,ClientHeight(window)-32,95,26,window,BUTTON_CANCEL)
+                               SetGadgetLayout(cancel,EDGE_ALIGNED,EDGE_CENTERED,EDGE_CENTERED,EDGE_ALIGNED)
+                       EndIf
+                       
+               Else
+                       If (flags & STYLE_CANCEL) Then
+                               cancel=CreateButton("{{btn_close}}",ClientWidth(window)-101,ClientHeight(window)-32,95,26,window,BUTTON_CANCEL)
+                               SetGadgetLayout(cancel,EDGE_CENTERED,EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED)
+                       EndIf
+               EndIf
+               
+               If (flags & STYLE_DIVIDER) And (flags & (STYLE_OK|STYLE_CANCEL)) Then
+                       divider = CreateLabel( "", 6, ClientHeight(window)-42, ClientWidth(window)-12, 4, window, LABEL_SEPARATOR )
+                       SetGadgetLayout(divider,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED)
+               EndIf
+               
+               If (flags & STYLE_MODAL) Then modal = True Else modal = False
+       
+       End Method
+       
+       Method Show()
+               Local   x,y,w,h,win:TGadget
+               If Not centered
+                       win=host.window         
+                       w=GadgetWidth(window)
+                       h=GadgetHeight(window)
+                       x=GadgetX(win)+(GadgetWidth(win)-w)/2
+                       y=GadgetY(win)+(GadgetHeight(win)-h)/2
+                       SetGadgetShape window,x,y,w,h
+                       centered=True
+               EndIf
+               host.HookRequester Self
+               ShowGadget window
+               ActivateGadget window
+               PollSystem
+       End Method
+       
+       Method Hide()
+               EnableGadget host.window
+               HideGadget window
+               host.UnhookRequester Self
+               host.SelectPanel host.currentpanel
+       End Method
+       Method IsModal()
+               Return modal
+       EndMethod
+       Method Poll()
+       End Method
+End Type
+
+Rem
+Type TProgressRequester Extends TRequester
+       Field   message$,value
+       Field   showing
+       Field   label:TGadget
+       Field   progbar:TGadget
+       
+       Method Show()   'returns false if cancelled
+               showing=True
+               Super.Show
+       End Method
+       
+       Method Hide()
+               showing=False
+               Super.Hide()
+       End Method
+       
+       Method Open(title$)
+               SetGadgetText window,title
+               Show
+       End Method
+       
+       Method Update(msg$,val)
+               If msg$<>message
+                       message=msg
+                       If label FreeGadget label
+                       label=CreateLabel(message,8,8,260,20,window)
+               EndIf
+               If showing And (val&$fc)<>(value&$fc)   'only update every 4 percent
+                       UpdateProgBar( progbar,val/100.0 )
+                       PollSystem
+               EndIf
+               value=val
+       End Method
+       
+       Function Create:TProgressRequester(host:TCodePlay)
+               Local   progress:TProgressRequester
+               progress=New TProgressRequester
+               progress.initrequester(host,"{{progress_window_title}}",280,128,STYLE_CANCEL)
+               progress.progbar=CreateProgBar( 8,32,260,20,progress.window )
+               Return progress
+       End Function
+End Type
+EndRem
+
+Type TPanelRequester Extends TRequester
+       Field   tabber:TGadget
+       Field   panels:TGadget[]
+       Field   index
+       
+       Method InitPanelRequester(owner:TCodeplay,label$,w=280,h=128)           
+               InitRequester owner,label,w,h,STYLE_OK|STYLE_CANCEL|STYLE_STDBORDER|STYLE_MODAL
+               tabber=CreateTabber(6,6,w-12,h-12,window)
+               SetGadgetLayout tabber,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+       End Method
+
+       Method SetPanelIndex(i)
+               HideGadget panels[index]
+               index=i
+               ShowGadget panels[index]
+               SelectGadgetItem tabber,index   
+       End Method
+       
+       Method SetPanel(panel:TGadget)
+               Local   i
+               For Local p:TGadget = EachIn panels
+                       If p=panel SetPanelIndex i;Exit
+                       i:+1
+               Next
+       End Method
+       
+       Method AddPanel:TGadget(name$)
+               Local   panel:TGadget
+               panel=CreatePanel(0,0,ClientWidth(tabber),ClientHeight(tabber),tabber)
+               SetGadgetLayout panel,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+               HideGadget panel
+               AddGadgetItem tabber,name,GADGETITEM_LOCALIZED
+               panels=panels[..panels.length+1]
+               panels[panels.length-1]=panel
+               Return panel
+       End Method
+       
+       Method RemovePanel(panel)
+       End Method
+       
+End Type
+
+Type TAboutRequester Extends TRequester
+       
+       Global pixLogo:TPixmap
+       
+       Field pnlLogo:TGadget, lblTitle:TGadget, lblSubtitle:TGadget
+       Field lblLeftAligned:TGadget[], lblRightAligned:TGadget[]
+       Field hypBlitz:TGadget
+       
+       Method PopulateText()
+               
+               Local strHeadings$[], strValues$[]
+               
+               strHeadings:+["{{about_label_bccver}}:"]
+               strValues:+[BCC_VERSION]
+               
+               strHeadings:+[""]
+               strValues:+[""]
+               
+               strHeadings:+["{{about_label_bmxpath}}:"]
+               ?Win32
+               strValues:+[BlitzMaxPath().Replace("/","\")]
+               ?Not Win32
+               strValues:+[BlitzMaxPath()]
+               ?
+               
+               ?Win32
+               strHeadings:+["{{about_label_mingwpath}}:"]
+               If getenv_("MINGW") Then
+                       strValues:+[getenv_("MINGW")]
+               Else
+                       strValues:+[LocalizeString("{{about_error_unavailable}}")]
+               EndIf
+               ?
+               
+               strHeadings:+[""]
+               strValues:+[""]
+               
+               ?Not MacOS
+               strHeadings:+["{{about_label_fasmver}}:"]
+               strValues:+[GetFASM()]
+               ?
+               
+               strHeadings:+["{{about_label_gccver}}:"]
+               strValues:+[GetGCC()]
+               
+               strHeadings:+["{{about_label_gplusplusver}}:"]
+               strValues:+[GetGpp()]
+               
+               PopulateColumns( strHeadings, strValues )
+       
+       EndMethod
+       
+       Function GetProcessOutput$(cmd$, flags$ = "")
+               
+               Local   version$
+               
+               ?Win32
+                       cmd:+".exe"
+               ?
+               
+               cmd=Quote(cmd)
+               If flags Then cmd:+" "+flags
+               
+               Local   process:TProcess = CreateProcess(cmd,HIDECONSOLE)
+               
+               If process
+                       Local bytes:Byte[]
+                       Local tmpTimeout:Int = MilliSecs() + 500
+                       Repeat
+                               Delay 10
+                               bytes=process.pipe.ReadPipe()
+                               If bytes
+                                       version:+String.FromBytes(bytes,bytes.length)
+                               EndIf
+                       Until (Not process.status()) Or (MilliSecs() > tmpTimeout)
+                       process.Close()
+                       Return version.Trim().Replace("~r","")
+               EndIf
+               
+               Return LocalizeString("{{about_error_unavailable}}")
+               
+       EndFunction
+       
+       Method GetFASM$()
+               ?Not MacOS
+                       Local tmpSections$[] = GetProcessOutput(BlitzMaxPath()+"/bin/fasm").Split("~n")[0].Split(" ")
+                       Return tmpSections[tmpSections.length-1]
+               ?
+       EndMethod
+       
+       Method GetGCC$()
+               ?Win32
+               If Not getenv_("MinGW") Then Return LocalizeString("{{about_error_notapplicable}}")
+               ?
+               Return GetProcessOutput("gcc", "-dumpversion").Split("~n")[0]
+       EndMethod
+       
+       Method GetGpp$()
+               ?Win32
+               If Not getenv_("MinGW") Then Return LocalizeString("{{about_error_notapplicable}}")
+               ?
+               Return GetProcessOutput("g++", "-dumpversion").Split("~n")[0]
+       EndMethod
+       
+       Method PopulateColumns( strHeadings$[], strValues$[] )
+               
+               strHeadings = strHeadings[..lblLeftAligned.length]
+               strValues = strValues[..lblRightAligned.length]
+               
+               For Local i:Int = 0 Until lblLeftAligned.length
+                       LocalizeGadget( lblLeftAligned[i], strHeadings[i] )
+               Next
+               
+               For Local i:Int = 0 Until lblRightAligned.length
+                       SetGadgetText( lblRightAligned[i], strValues[i] )
+                       SetGadgetToolTip( lblRightAligned[i], strValues[i] )
+               Next
+       
+       EndMethod
+       
+       Method Show()
+               PopulateText()
+               Super.Show()
+       EndMethod
+       
+       Method Poll()
+               Select EventSource()
+                       Case window
+                               If EventID()=EVENT_WINDOWCLOSE
+                                       Hide()
+                               EndIf                   
+                       Case cancel
+                               If EventID()=EVENT_GADGETACTION
+                                       Hide()
+                               EndIf
+                       Default
+                               Return 0
+               End Select
+               Return 1
+       End Method
+       
+       Function Create:TAboutRequester(host:TCodePlay)
+               
+               Local abt:TAboutRequester = New TAboutRequester
+               abt.initrequester(host,"{{about_window_title}}",420,255,STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL)
+               
+               Local win:TGadget = abt.window, w = ClientWidth(abt.window)-12, h = ClientHeight(abt.window)
+               
+               abt.pnlLogo = CreatePanel(w-(64-6),0,64,64,win)
+               SetGadgetLayout abt.pnlLogo, EDGE_CENTERED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_CENTERED
+               
+               'abt.pnlLogo = CreatePanel(0,0,64,64,win)
+               'SetGadgetLayout abt.pnlLogo, EDGE_ALIGNED, EDGE_CENTERED, EDGE_ALIGNED, EDGE_CENTERED
+               
+               If Not pixLogo Then pixLogo = LoadPixmapPNG("incbin::bmxlogo.png")
+               SetGadgetPixmap abt.pnlLogo, pixLogo, PANELPIXMAP_CENTER
+               
+               Local y = 12
+               
+               abt.lblTitle = CreateLabel("MaxIDE "+IDE_VERSION,6,y,w,18,win,LABEL_LEFT)
+               SetGadgetFont abt.lblTitle, LookupGuiFont( GUIFONT_SYSTEM, 12, FONT_BOLD )
+               SetGadgetLayout abt.lblTitle, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_CENTERED
+               y:+19
+               
+               abt.lblSubtitle = CreateLabel("Copyright Blitz Research Ltd.",6,y,w,22,win,LABEL_LEFT)
+               SetGadgetFont abt.lblSubtitle, LookupGuiFont( GUIFONT_SYSTEM, 10, FONT_ITALIC )
+               SetGadgetLayout abt.lblSubtitle, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_CENTERED
+               
+               y = 64
+               
+               SetGadgetLayout( CreateLabel("",6,y,w,4,win,LABEL_SEPARATOR), EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_CENTERED )
+               
+               y:+(4+6)
+               
+               Local tmpGadget:TGadget
+               
+               For y = y Until (255-21) Step 22
+                       
+                       tmpGadget = CreateLabel("",6,y,135,22,win,LABEL_LEFT)
+                       SetGadgetLayout( tmpGadget, EDGE_ALIGNED, EDGE_RELATIVE, EDGE_ALIGNED, EDGE_CENTERED )
+                       abt.lblLeftAligned:+[tmpGadget]
+
+                       tmpGadget = CreateLabel("",135+6,y,w-135,22,win,LABEL_LEFT)
+                       SetGadgetLayout( tmpGadget, EDGE_RELATIVE, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_CENTERED )
+                       DelocalizeGadget tmpGadget
+                       abt.lblRightAligned:+[tmpGadget]
+                       
+               Next
+               
+               abt.hypBlitz = CreateHyperlink("http://www.blitzbasic.com/",6,(h-28),200,26,win,LABEL_LEFT)
+               SetGadgetLayout abt.hypBlitz, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_CENTERED, EDGE_ALIGNED
+               
+               Return abt
+               
+       EndFunction
+       
+       Function Spacer( height:Int, inpout:Int Var )
+               inpout:+height+6
+               Return height
+       EndFunction
+
+EndType
+
+
+Type TCmdLineRequester Extends TRequester
+       Field   label:TGadget,textfield:TGadget
+
+       Method Poll()
+               Select EventSource()
+                       Case window
+                               If EventID()=EVENT_WINDOWCLOSE
+                                       Hide
+                               EndIf
+                       Case ok
+                               If EventID()=EVENT_GADGETACTION
+                                       host.SetCommandLine TextFieldText(textfield)
+                                       Hide
+                               EndIf                   
+                       Case cancel
+                               If EventID()=EVENT_GADGETACTION
+                                       SetGadgetText textfield,host.GetCommandLine()
+                                       Hide
+                               EndIf
+                       Default
+                               Return 0
+               End Select
+               Return 1
+       End Method
+       
+       Method Show()
+               SetGadgetText textfield,host.GetCommandLine()
+               Super.Show()
+               ActivateGadget textfield
+       End Method
+
+       Function Create:TCmdLineRequester(host:TCodePlay)
+               Local   cmd:TCmdLineRequester = New TCmdLineRequester
+               cmd.initrequester(host,"{{cmdline_window_title}}",260,60,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL)
+               cmd.label=CreateLabel("{{cmdline_label_cmdline}}:",6,8,260,20,cmd.window)
+               cmd.textfield=CreateTextField(6,30,ClientWidth(cmd.window)-12,21,cmd.window)
+               Return cmd
+       End Function
+End Type
+
+Type TGotoRequester Extends TRequester
+       Field   linenumber:TGadget
+
+       Method Show()
+               Super.Show()
+               ActivateGadget linenumber
+       End Method
+
+       Method Poll()
+               Local   line,data,text$
+               Select EventSource()
+                       Case linenumber
+                               If EventID() = EVENT_GADGETACTION
+                                       text = GadgetText(linenumber)
+                                       If text And (Int(text) <> text) Then SetGadgetText linenumber, Int(text)
+                               EndIf
+                       Case window
+                               If EventID()=EVENT_WINDOWCLOSE
+                                       Hide
+                               EndIf
+                       Case ok
+                               line=Int(GadgetText(linenumber))
+                               Hide
+                               host.activepanel.Invoke TOOLGOTO,String(line)
+                       Case cancel
+                               Hide
+                       Default
+                               Return 0
+               End Select
+               Return 1
+       End Method
+
+       Function Create:TGotoRequester(host:TCodePlay)
+               Local   seek:TGotoRequester = New TGotoRequester
+               seek.initrequester(host,"{{goto_window_title}}",260,66,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL,"{{goto_btn_goto}}")
+               CreateLabel("{{goto_label_linenum}}:",6,8+4,114,20,seek.window)
+               seek.linenumber=CreateTextField(150,8,ClientWidth(seek.window)-(150+6),21,seek.window)
+               SetGadgetFilter( seek.linenumber, IntegerFilter )
+               Return seek
+       End Function
+       
+       Function IntegerFilter:Int( event:TEvent, context:Object )
+               Select event.id
+                       Case EVENT_KEYCHAR
+                               If event.data >= Asc("0") And event.data <= Asc("9") Return True
+                               If event.data = 8 Or event.data = 127 Or event.data = 13 Return True
+                               Return False
+                       Case EVENT_KEYDOWN
+                               Return True
+               EndSelect
+       EndFunction
+       
+End Type
+
+Type TColor
+       Field   red,green,blue
+
+       Method Set(rgb)
+               red=(rgb Shr 16)&$FF
+               green=(rgb Shr 8)&$FF
+               blue=rgb&$FF
+       End Method
+
+       Method ToString$()
+               Return ""+red+","+green+","+blue
+       End Method
+
+       Method FromString(s$)
+               Local   p=s.Find(",")+1
+               If Not p Return
+               Local q=s.Find(",",p)+1
+               If Not q Return
+               red=Int(s[..p-1])
+               green=Int(s[p..q-1])
+               blue=Int(s[q..])
+       End Method
+
+       Method Request()
+               If RequestColor(red,green,blue)
+                       red=RequestedRed()
+                       green=RequestedGreen()
+                       blue=RequestedBlue()
+                       Return True
+               EndIf                           
+       End Method      
+End Type
+
+Type TTextStyle
+
+       Field   label:TGadget,panel:TGadget,combo:TGadget
+       Field   underline:TGadget, color:TColor
+       Field   flags
+       
+       Method Set(rgb,bolditalic)
+               color.set(rgb)
+               flags=bolditalic
+       End Method
+
+       Method Format(textarea:TGadget,pos,length,emphasise:Int = False)
+               Local tmpFlags:Int = flags
+               If emphasise Then tmpFlags:|TEXTFORMAT_BOLD
+               FormatTextAreaText textarea,color.red,color.green,color.blue,tmpFlags,pos,length
+       End Method
+
+       Method ToString$()
+               Return ""+color.red+","+color.green+","+color.blue+","+flags
+       End Method
+
+       Method FromString(s$)
+               Local   p,q,r
+               p=s.Find(",")+1;If Not p Return
+               q=s.Find(",",p)+1;If Not q Return
+               r=s.Find(",",q)+1;If Not r Return
+               color.red=Int(s[..p-1])
+               color.green=Int(s[p..q-1])
+               color.blue=Int(s[q..r-1])
+               flags=Int(s[r..])
+       End Method
+
+       Method Poll()
+               Select EventSource()
+                       Case panel
+                               If EventID()=EVENT_MOUSEDOWN
+                                       Return color.Request()
+                               EndIf
+                       Case combo
+                               flags=(flags&~3)|SelectedGadgetItem(combo)
+                               Return True
+                       Case underline
+                               If EventData() Then flags:|TEXTFORMAT_UNDERLINE Else flags:&~TEXTFORMAT_UNDERLINE
+                               Return True
+               End Select
+       End Method
+       
+       Method Refresh()
+               SetPanelColor panel,color.red,color.green,color.blue
+               SelectGadgetItem combo,flags&3
+               SetButtonState(underline,(flags&TEXTFORMAT_UNDERLINE <> 0))
+       End Method
+
+       Function Create:TTextStyle(name$,xpos,ypos,window:TGadget)
+               Local   s:TTextStyle
+               s=New TTextStyle
+               s.color=New TColor
+               s.label=CreateLabel(name,xpos,ypos+4,90,24,window)
+               s.panel=CreatePanel(xpos+94,ypos,24,24,window,PANEL_BORDER|PANEL_ACTIVE)
+               SetPanelColor s.panel,255,255,0
+               s.combo=CreateComboBox(xpos+122,ypos,96,24,window)
+               s.underline=CreateButton("{{txtstyle_underline}}",xpos+226,ypos,ClientWidth(window)-(xpos+220),24,window,BUTTON_CHECKBOX)
+               AddGadgetItem s.combo,"{{txtstyle_normal}}",GADGETITEM_LOCALIZED
+               AddGadgetItem s.combo,"{{txtstyle_bold}}",GADGETITEM_LOCALIZED
+               AddGadgetItem s.combo,"{{txtstyle_italic}}",GADGETITEM_LOCALIZED
+               AddGadgetItem s.combo,"{{txtstyle_bolditalic}}",GADGETITEM_LOCALIZED
+               Return s
+       End Function
+End Type
+
+Type TGadgetStyle
+       
+       Global fntLibrary:TGUIFont[] =  [TGuiFont(Null), LookupGuiFont(GUIFONT_SYSTEM), LookupGuiFont(GUIFONT_MONOSPACED), ..
+                                                       LookupGuiFont(GUIFONT_SANSSERIF), LookupGuiFont(GUIFONT_SERIF), ..
+                                                       LookupGuiFont(GUIFONT_SCRIPT) ]
+
+       Field   label:TGadget,fpanel:TGadget,bpanel:TGadget,fcombo:TGadget,fbutton:TGadget
+       Field   font_name$, font_size:Double
+       Field   fg:TColor, bg:TColor
+       Field   font_type = GUIFONT_SYSTEM, font:TGUIFont = fntLibrary[font_type]
+
+       Method Apply(gadget:TGadget)
+               SetGadgetFont gadget,font
+               SetGadgetColor gadget,bg.red,bg.green,bg.blue,True
+               SetGadgetColor gadget,fg.red,fg.green,fg.blue,False
+       End Method
+       
+       Method Set(fg_rgb,bg_rgb,ftype,fname$="",fsize=0)
+               fg.set(fg_rgb)
+               bg.set(bg_rgb)
+               If Not fntLibrary[ftype] Then
+                       font_name=fname
+                       font_size=fsize
+               Else
+                       font_name=FontName(fntLibrary[ftype])
+                       font_size=FontSize(fntLibrary[ftype])
+               EndIf
+               font_type=ftype
+       End Method
+
+       Method ToString$()
+               Return font_name+","+font_size+","+fg.ToString()+","+bg.ToString()+","+font_type
+       End Method
+       
+       Function GetArg$(a$ Var)
+               Local p = a.Find(",")
+               If p=-1 Then p=a.length
+               Local r$ = a$[..p]
+               a$=a$[p+1..]
+               Return r$
+       End Function
+       
+       Method FromString(s$)           
+               font_name=GetArg(s$)
+               font_size=Double(GetArg(s$))
+               fg.red=Int(GetArg(s$))
+               fg.green=Int(GetArg(s$))
+               fg.blue=Int(GetArg(s$))
+               bg.red=Int(GetArg(s$))
+               bg.green=Int(GetArg(s$))
+               bg.blue=Int(GetArg(s$))
+               font_type=Int(GetArg(s$))
+               If fntLibrary[font_type] Then
+                       font_name=FontName(fntLibrary[font_type])
+                       font_size=FontSize(fntLibrary[font_type])
+               EndIf
+       End Method
+
+       Method Poll()
+               Local   f:TGUIFont
+               Select EventSource()
+                       Case fpanel
+                               If EventID()=EVENT_MOUSEDOWN
+                                       Return fg.Request()
+                               EndIf
+                       Case bpanel
+                               If EventID()=EVENT_MOUSEDOWN
+                                       Return bg.Request()
+                               EndIf
+                       Case fcombo, fbutton
+                               If EventSource() = fcombo Then
+                                       If Not (EventData() < 0) Then
+                                               font_type = EventData()
+                                               f = fntLibrary[font_type]
+                                       EndIf
+                               Else
+                                       font_type = 0
+                                       SelectGadgetItem fcombo, font_type
+                               EndIf
+                               If Not f Then f=RequestFont(font)
+                               If f
+                                       font_name=FontName(f)
+                                       font_size=FontSize(f)
+                                       Return True
+                               EndIf                           
+               End Select
+       End Method
+       
+       Method Refresh()
+               font=fntLibrary[font_type]
+               If Not font Then font=LoadGuiFont(font_name,font_size)
+               SetPanelColor fpanel,fg.red,fg.green,fg.blue
+               SetPanelColor bpanel,bg.red,bg.green,bg.blue
+               SelectGadgetItem fcombo, font_type
+               Local tmpFloatText$[] = String(font_size).Split(".")
+               If tmpFloatText.length > 1 Then tmpFloatText[1] = tmpFloatText[1][..Min(2,tmpFloatText[1].length)]
+               SetGadgetText fbutton,font_name+" : "+".".Join(tmpFloatText)+"pt"
+       End Method
+
+       Function Create:TGadgetStyle(name$,xpos,ypos,window:TGadget)
+               Local   s:TGadgetStyle
+               s=New TGadgetStyle
+               s.fg=New TColor
+               s.bg=New TColor
+               s.label=CreateLabel(name,xpos,ypos+LABELOFFSET,66,50,window)
+               s.fpanel=CreatePanel(xpos+68,ypos,24,24,window,PANEL_BORDER|PANEL_ACTIVE)
+               s.bpanel=CreatePanel(xpos+96,ypos,24,24,window,PANEL_BORDER|PANEL_ACTIVE)
+               s.fbutton=CreateButton("..",xpos+122,ypos+30,ClientWidth(window)-(xpos+128),24,window)
+               s.fcombo=CreateComboBox(xpos+122,ypos,ClientWidth(window)-(xpos+128),24,window)
+               AddGadgetItem s.fcombo, "{{options_font_desc_user}}", GADGETITEM_DEFAULT|GADGETITEM_LOCALIZED
+               AddGadgetItem s.fcombo, "{{options_font_desc_guidefault}}", GADGETITEM_LOCALIZED
+               AddGadgetItem s.fcombo, "{{options_font_desc_monospaced}}", GADGETITEM_LOCALIZED
+               AddGadgetItem s.fcombo, "{{options_font_desc_sansserif}}", GADGETITEM_LOCALIZED
+               AddGadgetItem s.fcombo, "{{options_font_desc_serif}}", GADGETITEM_LOCALIZED
+               AddGadgetItem s.fcombo, "{{options_font_desc_script}}", GADGETITEM_LOCALIZED
+               Return s
+       End Function
+End Type
+
+Const NORMAL=0
+Const COMMENT=1
+Const QUOTED=2
+Const KEYWORD=3
+Const NUMBER=4
+Const MATCHING=5
+
+Type TOptionsRequester Extends TPanelRequester
+' panels
+       Field   optionspanel:TGadget,editorpanel:TGadget,toolpanel:TGadget
+' settings
+       Field   showtoolbar,restoreopenfiles,autocapitalize,syntaxhighlight,autobackup,autoindent,hideoutput
+       Field   bracketmatching, externalhelp,systemkeys,sortcode
+       Field   tabsize,language$
+       Field   editfontname$,editfontsize,editcolor:TColor
+       Field   outputfontname$,outputfontsize,outputcolor:TColor
+' states
+       Field   editfont:TGUIFont
+' gadgets
+       Field languages:TGadget
+       Field   tabbutton:TGadget
+       Field   editpanel:TGadget,editbutton:TGadget
+       Field   buttons:TGadget[11]
+       Field   styles:TTextStyle[]
+       Field   textarea:TGadget
+       Field   outputstyle:TGadgetStyle
+       Field   navstyle:TGadgetStyle
+       Field   dirty
+       Field   undo:TBank
+       
+       Method Show()
+               RefreshGadgets()
+               Super.Show()
+       EndMethod
+       
+       Method Snapshot()
+               If Not undo undo=CreateBank(8192)
+               Local stream:TStream=CreateBankStream(undo)
+               write stream
+               stream.close
+       End Method
+       
+       Method Restore()
+               If Not undo Return
+               Local stream:TStream=CreateBankStream(undo)
+               Read stream
+               stream.close
+       End Method
+
+       Method SetDefaults()
+               language=DEFAULT_LANGUAGEPATH
+               bracketmatching=True
+               showtoolbar=True
+               restoreopenfiles=True
+               autocapitalize=True
+               syntaxhighlight=True
+               autobackup=True
+               autoindent=True
+               tabsize=4
+               editfontname$=FontName(TGadgetStyle.fntLibrary[GUIFONT_MONOSPACED])
+               editfontsize=FontSize(TGadgetStyle.fntLibrary[GUIFONT_MONOSPACED])
+               editcolor.set( $334455 )
+               styles[NORMAL].set( $ffffff,0 )
+               styles[COMMENT].set( $bbeeff,0 )
+               styles[QUOTED].set( $00ff66,0 )
+               styles[KEYWORD].set( $ffff00,0 )
+               styles[NUMBER].set( $40ffff,0 )
+               styles[MATCHING].set( $ff4040,TEXTFORMAT_BOLD )
+               outputstyle.set(0,-1,GUIFONT_MONOSPACED)
+               navstyle.set(0,-1,GUIFONT_SYSTEM)
+               RefreshGadgets
+       End Method
+
+       Method Write(stream:TStream)
+               stream.WriteLine "[Options]"
+               stream.WriteLine "language="+language
+               stream.WriteLine "showtoolbar="+showtoolbar
+               stream.WriteLine "restoreopenfiles="+restoreopenfiles
+               stream.WriteLine "autocapitalize="+autocapitalize
+               stream.WriteLine "syntaxhighlight="+syntaxhighlight
+               stream.WriteLine "bracketmatching="+bracketmatching
+               stream.WriteLine "autobackup="+autobackup
+               stream.WriteLine "autoindent="+autoindent
+               stream.WriteLine "tabsize="+tabsize
+               stream.WriteLine "editfontname="+editfontname
+               stream.WriteLine "editfontsize="+editfontsize
+               stream.WriteLine "editcolor="+editcolor.ToString()
+               stream.WriteLine "normal_style="+styles[NORMAL].ToString()
+               stream.WriteLine "comment_style="+styles[COMMENT].ToString()
+               stream.WriteLine "quote_style="+styles[QUOTED].ToString()
+               stream.WriteLine "keyword_style="+styles[KEYWORD].ToString()
+               stream.WriteLine "number_style="+styles[NUMBER].ToString()
+               stream.WriteLine "matched_style="+styles[MATCHING].ToString()
+               stream.WriteLine "console_style="+outputstyle.ToString()        'Renamed from 'output_style' to bump users to default monospace font.
+               stream.WriteLine "navi_style="+navstyle.ToString()      'Renamed from 'nav_style' to bump users to default treeview font.
+               stream.WriteLine "hide_output="+hideoutput
+               stream.WriteLine "external_help="+externalhelp
+               stream.WriteLine "system_keys="+systemkeys
+               stream.WriteLine "sort_code="+sortcode
+       End Method
+
+       Method Read(stream:TStream)
+               Local   f$,p,a$,b$,t
+               While Not stream.Eof()
+                       f$=stream.ReadLine()
+                       If f$="" Or (f$[..1]="[" And f$<>"[Options]") Exit
+                       p=f.find("=")
+                       a$=f[..p]
+                       b$=f[p+1..]
+                       t=Int(b)
+                       Select a$
+                               Case "showtoolbar" showtoolbar=t
+                               Case "restoreopenfiles" restoreopenfiles=t
+                               Case "autocapitalize" autocapitalize=t
+                               Case "syntaxhighlight" syntaxhighlight=t
+                               Case "bracketmatching" bracketmatching=t
+                               Case "autobackup" autobackup=t
+                               Case "autoindent" autoindent=t
+                               Case "tabsize" tabsize=t                
+                               Case "editfontname" editfontname=b
+                               Case "editfontsize" editfontsize=t
+                               Case "editcolor" editcolor.FromString(b)                
+                               Case "normal_style" styles[NORMAL].FromString(b)
+                               Case "comment_style" styles[COMMENT].FromString(b)
+                               Case "quote_style" styles[QUOTED].FromString(b)
+                               Case "keyword_style" styles[KEYWORD].FromString(b)
+                               Case "number_style" styles[NUMBER].FromString(b)
+                               Case "matched_style" styles[MATCHING].FromString(b)
+                               Case "console_style" outputstyle.FromString(b)  'Renamed from 'output_style' to bump users to default monospace font.
+                               Case "navi_style" navstyle.FromString(b)        'Renamed from 'nav_style' to bump users to default treeview font.
+                               Case "hide_output" hideoutput=t
+                               Case "external_help" externalhelp=t
+                               Case "system_keys" systemkeys=t
+                               Case "sort_code" sortcode=t
+                               Case "language"
+                                       Try
+                                               Local tmpLanguage:TMaxGUILanguage = LoadLanguage(host.FullPath(b))
+                                               If tmpLanguage Then
+                                                       language = b
+                                                       SetLocalizationLanguage tmpLanguage
+                                                       host.RefreshMenu()
+                                               EndIf
+                                       Catch excn:Object
+                                       EndTry
+                       End Select
+               Wend            
+               RefreshGadgets
+       End Method
+       
+       Method RefreshGadgets()
+               Local   rgb:TColor,flags
+               editfont=LoadGuiFont(editfontname,editfontsize)
+               
+               'Language Loading / Enumeration
+               ClearGadgetItems languages
+               AddGadgetItem languages, "English (English) [Embedded]", GADGETITEM_DEFAULT,-1,"",DEFAULT_LANGUAGEPATH
+               For Local tmpFile$ = EachIn LoadDir( host.bmxpath+"/cfg", True )
+                       Local tmpPath$ = host.bmxpath+"/cfg/"+tmpFile
+                       If FileType(tmpPath) = FILETYPE_FILE And tmpFile.ToLower().EndsWith(".language.ini") Then
+                               If tmpPath = host.FullPath(language) Then flags = GADGETITEM_DEFAULT Else flags = 0
+                               AddGadgetItem languages, tmpFile.Split(".")[0], flags, -1, "", "$BMXPATH/cfg/"+tmpFile
+                       EndIf
+               Next
+               
+               SetButtonState buttons[0],showtoolbar
+               SetButtonState buttons[1],restoreopenfiles
+               SetButtonState buttons[2],autocapitalize
+               SetButtonState buttons[3],syntaxhighlight
+               SetButtonState buttons[4],bracketmatching
+               SetButtonState buttons[5],autobackup
+               SetButtonState buttons[6],autoindent
+               SetButtonState buttons[7],hideoutput
+               SetButtonState buttons[8],externalhelp
+               SetButtonState buttons[9],systemkeys
+               SetButtonState buttons[10],sortcode
+               SelectGadgetItem tabbutton,Min(Max(tabsize/2-1,0),7)
+               SetPanelColor editpanel,editcolor.red,editcolor.green,editcolor.blue
+               SetGadgetText editbutton,editfontname+" : "+editfontsize + "pt"
+               For Local i:Int = 0 Until styles.length
+                       styles[i].Refresh
+               Next
+               LockTextArea textarea
+               SetTextAreaColor textarea,editcolor.red,editcolor.green,editcolor.blue,True
+               SetGadgetFont textarea,editfont
+               styles[NORMAL].format(textarea,0,TEXTAREA_ALL)
+               styles[COMMENT].format(textarea,0,12)
+               styles[MATCHING].format(textarea,24,1)
+               styles[NUMBER].format(textarea,25,3)
+               styles[NUMBER].format(textarea,31,1)
+               styles[MATCHING].format(textarea,32,1)
+               styles[NUMBER].format(textarea,36,1)
+               styles[KEYWORD].format(textarea,39,5)
+               styles[QUOTED].format(textarea,46,10)
+               UnlockTextArea textarea
+               outputstyle.Refresh
+               navstyle.Refresh
+               dirty=True
+       End Method
+
+       Method Poll()
+               Local   font:TGUIFont,refresh,processed = 1
+               For Local i:Int = 0 Until styles.length
+                       refresh:|styles[i].Poll()
+               Next
+               refresh:|outputstyle.Poll()
+               refresh:|navstyle.Poll()
+               Select EventID()
+                       Case EVENT_GADGETACTION, EVENT_WINDOWCLOSE
+                               Select EventSource()
+                                       Case buttons[0];showtoolbar=ButtonState(buttons[0]);dirty=True
+                                       Case buttons[1];restoreopenfiles=ButtonState(buttons[1])
+                                       Case buttons[2];autocapitalize=ButtonState(buttons[2]);dirty=True
+                                       Case buttons[3];syntaxhighlight=ButtonState(buttons[3]);dirty=True
+                                       Case buttons[4];bracketmatching=ButtonState(buttons[4])
+                                       Case buttons[5];autobackup=ButtonState(buttons[5])
+                                       Case buttons[6];autoindent=ButtonState(buttons[6])
+                                       Case buttons[7];hideoutput=ButtonState(buttons[7])
+                                       Case buttons[8];externalhelp=ButtonState(buttons[8])
+                                       Case buttons[9];systemkeys=ButtonState(buttons[9]);dirty=2
+                                       Case buttons[10];sortcode=ButtonState(buttons[10]);dirty=3
+                                       Case tabber;SetPanelIndex SelectedGadgetItem(tabber)
+                                       Case ok
+                                               Hide()
+                                               Select dirty
+                                                       Case 1
+                                                               host.RefreshAll
+                                                       Case 2
+                                                               host.Restart
+                                               End Select
+                                               dirty=False
+                                               SnapShot()
+                                       Case window
+                                               If EventID()=EVENT_WINDOWCLOSE
+                                                       Restore()
+                                                       dirty=False
+                                                       Hide()
+                                               EndIf
+                                       Case cancel
+                                               Restore()
+                                               dirty=False
+                                               Hide()
+                                       Case tabbutton
+                                               tabsize=(SelectedGadgetItem(tabbutton)+1)*2
+                                               refresh=True
+                                       Case editpanel
+                                               If EventID()=EVENT_MOUSEDOWN
+                                                       refresh=editcolor.Request()
+                                               EndIf
+                                       Case editbutton
+                                               font=RequestFont(editfont)
+                                               If font
+                                                       editfontname=FontName(font)
+                                                       editfontsize=FontSize(font)
+                                                       refresh=True
+                                               EndIf
+                                       Case languages
+                                               If EventData() > 0 Then
+                                                       language = String(GadgetItemExtra(languages,EventData()))
+                                                       SetLocalizationLanguage TMaxGUILanguage(LoadLanguage(host.FullPath(language)))
+                                               Else
+                                                       language = DEFAULT_LANGUAGEPATH
+                                                       SetLocalizationLanguage defaultLanguage
+                                               EndIf
+                                               host.RefreshMenu()
+                                       Default
+                                               processed = 0
+                               EndSelect
+                       Case EVENT_MOUSEDOWN
+                               Select EventSource()
+                                       Case editpanel
+                                               If EventID()=EVENT_MOUSEDOWN
+                                                       editcolor.Request()
+                                                       refresh=True
+                                               EndIf
+                                       Default
+                                               processed = 0
+                               EndSelect
+               EndSelect
+               If refresh Then RefreshGadgets()
+               Return processed
+       End Method
+       
+       Method InitOptionsRequester(host:TCodePlay)             
+               Local   w:TGadget
+               InitPanelRequester(host,"{{options_window_title}}",380,430)
+' init values
+               editcolor=New TColor
+' init gadgets
+               optionspanel=AddPanel("{{options_optionstab}}")
+               editorpanel=AddPanel("{{options_editortab}}")
+               toolpanel=AddPanel("{{options_toolstab}}")
+               
+               SetGadgetShape( tabber, GadgetX(tabber), GadgetY(tabber)+32, GadgetWidth(tabber), GadgetHeight(tabber)-32 )
+               
+               w=window
+               CreateLabel("{{options_options_label_language}}:",6,6+4,80,24,w)
+               languages = CreateComboBox(90,6,ClientWidth(w)-96,26,w)
+
+               w=optionspanel
+               
+               buttons[0]=CreateButton("{{options_options_btn_showtoolbar}}",6,6,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX)
+               buttons[1]=CreateButton("{{options_options_btn_autorestore}}",6,34,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX)
+               buttons[2]=CreateButton("{{options_options_btn_autocaps}}",6,60,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX)
+               buttons[3]=CreateButton("{{options_options_btn_syntaxhighlight}}",6,86,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX)
+               buttons[4]=CreateButton("{{options_options_btn_bracketmatching}}",6,112,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX)
+               buttons[5]=CreateButton("{{options_options_btn_autobackup}}",6,138,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX)
+               buttons[6]=CreateButton("{{options_options_btn_autoindent}}",6,164,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX)
+               buttons[7]=CreateButton("{{options_options_btn_autohideoutput}}",6,190,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX)
+               buttons[8]=CreateButton("{{options_options_btn_useexternalbrowser}}",6,216,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX)
+               buttons[9]=CreateButton("{{options_options_btn_osshortcuts}}",6,242,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX)
+               buttons[10]=CreateButton("{{options_options_btn_sortcodeviewnodes}}",6,268,ClientWidth(w)-12,26,w,BUTTON_CHECKBOX)
+
+               w=editorpanel
+               CreateLabel("{{options_editor_label_background}}:",6,6+4,90,24,w)
+               editpanel=CreatePanel(100,6,24,24,w,PANEL_BORDER|PANEL_ACTIVE)
+               editbutton=CreateButton("..",128,6,ClientWidth(w)-134,24,w)
+               
+               tabbutton=CreateComboBox(128,36,ClientWidth(w)-134,24,w)
+               For Local i=1 To 8
+                       AddGadgetItem tabbutton,"{{options_editor_itemlabel_tabsize}} "+(i*2),GADGETITEM_LOCALIZED
+               Next
+               
+               styles=New TTextStyle[6]
+               styles[NORMAL]=TTextStyle.Create("{{options_editor_label_plaintext}}:",6,66,w)
+               styles[COMMENT]=TTextStyle.Create("{{options_editor_label_remarks}}:",6,96,w)
+               styles[QUOTED]=TTextStyle.Create("{{options_editor_label_strings}}:",6,126,w)
+               styles[KEYWORD]=TTextStyle.Create("{{options_editor_label_keywords}}:",6,156,w)
+               styles[NUMBER]=TTextStyle.Create("{{options_editor_label_numbers}}:",6,186,w)
+               styles[MATCHING]=TTextStyle.Create("{{options_editor_label_matchings}}:",6,216,w)
+               
+               textarea=CreateTextArea(6,250,ClientWidth(w)-12,ClientHeight(w)-256,w,TEXTAREA_READONLY)
+               SetGadgetText textarea,"'Sample Code~n~nresult = ((2.0 * 4) + 1)~nPrint( ~qResult: ~q + result )~n"
+               
+               w=toolpanel
+               outputstyle=TGadgetStyle.Create("{{options_tools_label_output}}: ",6,6,w)
+               navstyle=TGadgetStyle.Create("{{options_tools_label_navbar}}: ",6,66,w)
+
+               SetDefaults()
+               SetPanel optionspanel
+               
+               SnapShot
+       End Method
+       
+       Function Create:TOptionsRequester(host:TCodePlay)
+               Local   o:TOptionsRequester
+               o=New TOptionsRequester
+               o.InitOptionsRequester host
+               Return o
+       End Function
+       
+End Type
+
+Type TFindRequester Extends TRequester
+       Field   findterm:TGadget
+       
+       Method ShowFind(term$="")
+               If term SetGadgetText(findterm,term)
+               Super.Show()
+               ActivateGadget findterm
+       End Method
+
+       Method Poll()
+               Local   find$,data              
+               Select EventSource()
+                       Case window
+                               If EventID()=EVENT_WINDOWCLOSE
+                                       Hide()
+                               EndIf
+                       Case ok
+                               If EventID() = EVENT_GADGETACTION
+                                       If TextFieldText(findterm)
+                                               find=TextFieldText(findterm)
+                                               Hide()
+                                               host.activepanel.Invoke TOOLFINDNEXT,find
+                                       Else
+                                               Notify LocalizeString("{{search_error_nosearchstring}}"), True
+                                               ActivateGadget findterm
+                                       EndIf
+                               EndIf
+                       Case cancel
+                               If EventID() = EVENT_GADGETACTION Then Hide()
+                       Default
+                               Return 0
+               End Select
+               Return 1
+       End Method
+
+       Function Create:TFindRequester(host:TCodePlay)
+               Local   seek:TFindRequester
+               seek=New TFindRequester
+               seek.initrequester(host,"{{find_window_title}}",280,66,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL,"{{find_btn_find}}")
+               CreateLabel("{{find_label_find}}:",6,12,82,24,seek.window)
+               seek.findterm=CreateTextField(88,8,ClientWidth(seek.window)-(88+6),21,seek.window)
+               Return seek
+       End Function
+End Type
+
+Type TReplaceRequester Extends TRequester
+       Field   findterm:TGadget,replaceterm:TGadget
+       Field   findnext:TGadget,replaceit:TGadget,replaceall:TGadget
+       
+       Method Show()
+               Super.Show()
+               ActivateGadget findterm
+       End Method
+
+       Method Poll()
+               Local   find$,Replace$
+               Select EventSource()
+                       Case window
+                               If EventID()=EVENT_WINDOWCLOSE
+                                       Hide()
+                               EndIf
+                       Case cancel
+                               If EventID() = EVENT_GADGETACTION Then Hide
+                       Case ok
+                               If EventID() = EVENT_GADGETACTION Then
+                                       If TextFieldText(findterm) Then
+                                               find=TextFieldText(findterm)
+                                               host.activepanel.Invoke TOOLFINDNEXT,find
+                                       Else
+                                               Notify LocalizeString("{{search_error_nosearchstring}}"), True
+                                               ActivateGadget findterm
+                                       EndIf
+                               EndIf
+                       Case replaceit
+                               If EventID() = EVENT_GADGETACTION Then
+                                       Replace=TextFieldText(replaceterm)
+                                       If host.activepanel.Invoke(TOOLREPLACE,Replace)
+                                               host.activepanel.Invoke TOOLFINDNEXT,find
+                                       EndIf
+                               EndIf
+                       Case replaceall
+                               If EventID() = EVENT_GADGETACTION Then
+                                       find=TextFieldText(findterm)
+                                       Replace=TextFieldText(replaceterm)
+                                       host.activepanel.Invoke TOOLREPLACE,find+Chr(0)+Replace
+                               EndIf
+                       Default
+                               Return 0
+               End Select
+               Return 1
+       End Method
+
+       Function Create:TReplaceRequester(host:TCodePlay)
+               Local x,y
+               Local   seek:TReplaceRequester
+               seek=New TReplaceRequester
+               seek.initrequester(host,"{{replace_window_title}}",380,80,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER,"{{replace_btn_findnext}}")
+               
+               y=11
+               CreateLabel( "{{replace_label_find}}:",6,y+4,88,24,seek.window )
+               seek.findterm=CreateTextField( 96,y,168,21,seek.window )
+
+               y:+32           
+               CreateLabel( "{{replace_label_replacewith}}:",6,y+4,88,24,seek.window )
+               seek.replaceterm=CreateTextField( 96,y,168,21,seek.window )
+
+               x=ClientWidth(seek.window)-102
+               y=8
+               seek.replaceit=CreateButton("{{replace_btn_replace}}",x,y,96,26,seek.window)
+               seek.replaceall=CreateButton("{{replace_btn_replaceall}}",x,y+32,96,26,seek.window)
+               
+               Return seek
+       End Function
+End Type
+
+Type TEventHandler Extends TTool
+       Method OnEvent() Abstract
+End Type
+
+Type TToolPanel Extends TEventHandler
+       Field   name$,path$
+       Field   panel:TGadget
+       Field   index
+       Field   active
+       
+       Method Show()
+       End Method
+End Type
+
+Type TView
+       Field   node:TGadget
+       Field   state
+End Type
+
+Type TNode Extends TTool
+       Const   HIDESTATE=0
+       Const   CLOSEDSTATE=1
+       Const   OPENSTATE=2
+
+       Field   name$,sortname$
+       Field   parent:TNode
+       Field   kids:TList=New TList
+       Field   views:TView[]
+' activate program     
+       Field   target:TTool
+       Field   action
+       Field   argument:Object
+
+       Method SortKids( ascending=True )
+               Local term:TLink=kids._head
+               Repeat
+                       Local link:TLink=kids._head._succ
+                       Local sorted=True
+                       Repeat
+                               Local succ:TLink=link._succ
+                               If succ=term Exit
+                               Local cc=TNode(link._value).sortname.Compare( TNode(succ._value).sortname )
+                               If (cc>0 And ascending) Or (cc<0 And Not ascending)
+                                       Local link_pred:TLink=link._pred
+                                       Local succ_succ:TLink=succ._succ
+                                       link_pred._succ=succ
+                                       succ._succ=link
+                                       succ._pred=link_pred
+                                       link._succ=succ_succ
+                                       link._pred=succ
+                                       succ_succ._pred=link
+                                       sorted=False
+                               Else
+                                       link=succ
+                               EndIf
+                       Forever
+                       If sorted Return
+                       term=link
+               Forever
+       End Method
+
+       Method FindArgument:TNode(arg:Object)
+               Local   n:TNode,r:TNode,a$
+               If arg.Compare(argument)=0 Return Self
+               a$=(String(arg)).ToLower()
+               If a And a=(String(argument)).toLower() Return Self
+               For n=EachIn kids
+                       r=n.FindArgument(arg)
+                       If r Return r
+               Next
+       End Method
+       
+       ?Debug
+       Method Dump(indent$="")
+               Local   n:TNode         
+               Print indent+name
+               indent:+"~t"
+               For n=EachIn kids
+                       n.Dump indent
+               Next
+       End Method              
+       ?
+       
+       Method IsHidden()
+               Local   v:TView
+               If Not parent Return False
+               For v=EachIn parent.views
+                       If v.state=OPENSTATE Return False
+               Next
+               Return True
+       End Method
+       
+       Method SetAction(tool:TTool,cmd,arg:Object=Null)
+               target=tool
+               action=cmd
+               argument=arg
+       End Method
+
+       Method Hide(v:TView=Null)       'null means hide in all views
+               For Local n:TNode = EachIn kids
+                       n.hide v
+               Next
+               If v
+                       If v.node FreeTreeViewNode v.node;v.node=Null
+               Else
+                       For v=EachIn views
+                               If v.node FreeTreeViewNode v.node;v.node=Null
+                       Next
+               EndIf
+       End Method
+       
+       Method Detach()
+               Hide()
+               If parent parent.kids.remove Self;parent=Null
+       End Method
+       
+       Method FreeKids()
+               For Local n:TNode = EachIn kids
+                       n.free
+               Next
+       End Method
+       
+       Method Free()
+               FreeKids()
+               Detach()
+               target=Null;argument=Null;views=Null
+       End Method
+       
+       Method Invoke(command,arg:Object=Null)
+               Select command
+               Case TOOLACTIVATE
+                       If target Return target.Invoke(action,argument)
+               End Select
+       End Method
+       
+       Method Find:TNode(treeviewnode:TGadget,view=0)
+               Local   n:TNode,r:TNode
+               Local   v:TView
+               v=getview(view)
+               If v And v.node=treeviewnode Return Self
+               For n=EachIn kids
+                       r=n.Find(treeviewnode,view)
+                       If r Return r
+               Next
+       End Method
+       
+       Method SetNode(treeviewnode:TGadget,view=0)
+               Local   v:TView = getview(view)
+               v.node=treeviewnode
+               open view
+       End Method
+       
+       Method HighLight(view=-1)
+               Local   v:TView
+               If view=-1
+                       For view=0 Until views.length
+                               HighLight view
+                       Next
+                       Return
+               EndIf
+               v=GetView(view)
+               If v.node SelectTreeViewNode v.node
+       End Method
+       
+       Method Open(view=-1)
+               Local   v:TView
+               If view=-1
+                       For view=0 Until views.length
+                               Open view
+                       Next
+                       Return
+               EndIf
+               v=GetView(view)
+               If v.state<>OPENSTATE
+                       v.state=OPENSTATE
+                       RefreshView view
+'                      If v.node ExpandTreeViewNode v.node
+               EndIf
+       End Method
+       
+       Method Close(view=0)
+               Local   v:TView = GetView(view)
+               If v.state<>CLOSEDSTATE
+                       v.state=CLOSEDSTATE
+'                      If v.node CollapseTreeViewNode v.node
+               EndIf
+       End Method
+       
+       Method GetState(view=0)
+               Return GetView(view).state
+       End Method
+
+       Method GetView:TView(view=0)
+               If view>=views.length
+                       views=views[..view+1]
+               EndIf
+               If Not views[view] views[view] = New TView
+               Return views[view]
+       End Method
+       
+       Method GetIndex()
+               Local   node:TNode
+               Local   i               
+               If parent
+                       For node=EachIn parent.kids
+                               If node=Self Return i
+                               i:+1
+                       Next
+               EndIf
+       End Method
+       
+       Method Refresh()
+               For Local i:Int = 0 Until views.length
+                       RefreshView i
+               Next
+       End Method
+       
+       Method RefreshView(view=0)
+               Local   n:TNode,quick,nodeToOpen:TGadget
+               Local   v:TView,vv:TView
+               Local   node
+               If parent And parent.getstate(view)=CLOSEDSTATE quick=True              
+               v=getview(view)
+               If v.node And parent
+                       If GadgetText(v.node) <> name Then
+                               ModifyTreeViewNode v.node,name
+                               LocalizeGadget(v.node,name,"")
+                       EndIf
+                       If v.state=OPENSTATE nodeToOpen = v.node;quick = False
+               Else
+                       If parent And name
+                               vv=parent.getview(view)
+                               If vv.node
+                                       v.node=InsertTreeViewNode(GetIndex(),name,vv.node)
+                                       If v.state=HIDESTATE v.state=CLOSEDSTATE                                        
+                                       If vv.state=OPENSTATE nodeToOpen = vv.node
+                                       quick=False
+                               EndIf
+                       EndIf
+               EndIf
+               If quick Return
+               If Not kids Return
+               For n=EachIn kids
+                       n.RefreshView view
+               Next
+               If nodeToOpen Then ExpandTreeViewNode nodeToOpen
+       End Method
+
+       Method NodeAfter:TNode(node:TNode)
+               Local   link:TLink
+               If node link=kids.FindLink(node)
+               If link link=link.NextLink()
+               If link Return TNode(link.Value())      
+       End Method
+
+       Method Sync(snap:TNode)
+               Local   snapkid:TNode
+               Local   currentkid:TNode
+               Local   kid:TNode
+               Local   t:TNode
+               Local   link:TLink
+
+               If snap.name<>name Return
+               If kids.Count() currentkid=TNode(kids.First())
+               For snapkid=EachIn snap.kids
+' if same name in list
+                       kid=currentkid
+                       While kid
+                               If kid.name=snapkid.name Exit
+                               kid=NodeAfter(kid)
+                       Wend
+' then remove entries in front                 
+                       If kid
+                               While currentkid<>kid
+                                       t=currentkid
+                                       currentkid=NodeAfter(currentkid)                        
+                                       t.free()
+                               Wend
+                       EndIf
+' if same name sync else insert
+                       If currentkid And currentkid.name=snapkid.name  'merge values if same name
+                               currentkid.Sync snapkid
+                               currentkid=NodeAfter(currentkid)
+                       Else
+                               snapkid.detach
+                               If currentkid
+                                       link=kids.FindLink(currentkid)
+                                       kids.InsertBeforeLink snapkid,link
+                               Else
+                                       kids.AddLast snapkid
+                               EndIf
+                               snapkid.parent=Self
+                       EndIf
+               Next
+' remove any entries at end
+               While currentkid
+                       t=currentkid
+                       currentkid=NodeAfter(currentkid)                        
+                       t.free()
+               Wend
+               Refresh()
+       End Method
+
+       Method SetName(n$)
+               name=n
+       End Method
+               
+       Method AddNode:TNode(name$)
+               Local   v:TNode
+               v=New TNode
+               v.setname name
+               Append v
+               Return v
+       End Method
+       
+       Method Append(v:TNode)
+               v.parent=Self
+               kids.AddLast v
+       End Method      
+       
+       Function CreateNode:TNode(name$)
+               Local   node:TNode
+               node=New TNode
+               node.setname name
+               Return node
+       End Function
+       
+End Type
+
+Type THelpPanel Extends TToolPanel
+
+       Field host:TCodePlay
+       Field htmlview:TGadget
+
+       Method AddLink:TNode(parent:TNode,name$,href$)
+               Local   n:TNode
+               If parent
+                       n=parent.AddNode(name)
+               Else
+                       n=host.helproot
+               EndIf
+               If href href=RealPath(href)
+               n.SetAction(Self,TOOLNAVIGATE,href)
+               Return n
+       End Method
+
+       Method ImportLinks( node:TNode,path$ )
+
+               Local t$=path+"/index.html"
+               If FileType( t )<>FILETYPE_FILE Return
+
+               node=AddLink( node,StripDir( path ),t )
+
+               Local map:TMap=New TMap
+               
+               'scan for html files
+               For Local e$=EachIn LoadDir( path )
+                       If e="index.html" Continue
+                       Local p$=path+"/"+e
+                       Select FileType( p )
+                       Case FILETYPE_DIR
+                               ImportLinks node,p
+                       Case FILETYPE_FILE
+                               If Not e.StartsWith( "_" ) And ExtractExt( e ).Tolower()="html"
+                                       map.Insert StripExt( e ),p
+                               EndIf
+                       End Select
+               Next
+
+               'scan for anchors in index.html...
+               '
+               'note: anchors must be quote enclosed and of simple form <a name="blah">
+               Local c$=CacheAndLoadText( t ),i
+               Repeat
+                       i=c.Find( "<a name=~q",i )
+                       If i=-1 Exit
+                       i:+9
+                       Local i2=c.Find( "~q>",i )
+                       If i2=-1 Exit
+                       Local q$=c[i..i2]
+                       If q.StartsWith( "_" ) Continue
+                       map.Insert q,t+"#"+q
+                       i=i2+1
+               Forever
+
+               For Local kv:TKeyValue=EachIn map
+                       AddLink node,String( kv.Key() ),String( kv.Value() )
+               Next
+
+       End Method
+
+       Method SyncDocs()
+               host.helproot.FreeKids
+
+               ImportLinks Null,host.bmxpath+"/docs/html"
+
+               Local link:TNode
+               For Local m$=EachIn EnumModules()
+                       If m.StartsWith( "brl." ) Or m.StartsWith( "pub." ) Or m.StartsWith("maxgui.") Continue
+                       Local p$=ModulePath( m )+"/doc/commands.html"
+                       If FileType( p )<>FILETYPE_FILE Continue
+                       If Not link link=AddLink( host.helproot,"{{navnode_thirdpartymods}}","" )
+                       AddLink link,m,p
+               Next
+
+               link=AddLink( host.helproot,"{{navnode_moduleindex}}","" )
+               
+               If FileType( host.bmxpath+"/docs/html/Modules/commands.txt" )=FILETYPE_FILE
+                       Local comm$=CacheAndLoadText( host.bmxpath+"/docs/html/Modules/commands.txt" )
+                       For Local line$=EachIn comm.Split( "~n" )
+                               Local bits$[]=line.Split( "|" )
+                               If bits.length<>2 Continue
+                               Local i=bits[0].Find( " : " )
+                               If i<>-1 bits[0]=bits[0][..i]
+                               AddLink link,bits[0],host.bmxpath+bits[1]
+                       Next
+               EndIf
+                       
+               host.helproot.Refresh
+       End Method
+
+       Method Invoke(command,argument:Object=Null)
+               Local   href$
+               If Not htmlview Return
+               Select command
+                       Case TOOLCUT
+                               GadgetCut htmlview
+                       Case TOOLCOPY
+                               GadgetCopy htmlview
+                       Case TOOLPASTE
+                               GadgetPaste htmlview
+                       Case TOOLSHOW
+                               ActivateGadget htmlview 
+                               host.SetTitle
+                       Case TOOLNAVIGATE
+                               href$=String(argument)
+                               If href Go href
+                       Case TOOLPRINT
+                               GadgetPrint htmlview
+               End Select
+       End Method
+
+       Method OnEvent()
+               Local   url$,p,t$
+               If EventSource()=htmlview
+                       Select EventID()
+                               Case EVENT_GADGETACTION                         'NAVIGATEREQUEST
+                                       url$=String( EventExtra() )
+                                       If url[..5]="http:"
+                                               OpenURL url
+                                       Else
+                                               p=url.findlast(".")
+                                               If p>-1
+                                                       t$=url[p..].tolower()
+                                                       If t$=".bmx"
+                                                               If url.Find( "file://" )=0
+                                                                       url=url[7..]
+                                                                       ?Win32
+                                                                       url=url[1..]
+                                                                       ?
+                                                               EndIf
+                                                               url=url.Replace("%20"," ")
+                                                               Local source:TOpenCode=host.OpenSource(url)
+                                                               If source source.MakePathTemp
+                                                       Else
+                                                               url=url.Replace("\","/")
+                                                               url=url.Replace("user/index","user/welcome")
+                                                               url=url.Replace("lang/index","lang/welcome")
+                                                               url=url.Replace("mods/index","mods/welcome")
+                                                               Go url$
+                                                       EndIf
+                                               EndIf
+                                       EndIf
+                       End Select                      
+               EndIf
+       End Method
+       
+       Method Go(url$,internal=False)
+               Local   node:TNode
+
+               If host.options.externalhelp And Not internal
+                       PollSystem
+                       OpenURL url
+                       MinimizeWindow host.window
+                       PollSystem
+                       Return
+               EndIf
+
+               HtmlViewGo htmlview,url
+               host.SelectPanel Self
+               node=host.helproot.FindArgument(RealPath(url))
+               If node
+                       node.Highlight
+'              Else
+'                      print "node not found"
+               EndIf           
+               ActivateGadget htmlview                 
+       End Method
+       
+       Method Home()
+               Go host.bmxpath+HOMEPAGE,True
+       End Method
+       
+       Method Forward()
+               HtmlViewForward htmlview
+       End Method
+
+       Method Back()
+               HtmlViewBack htmlview
+       End Method
+
+       Function Create:THelpPanel(host:TCodePlay)
+               Local   root,style
+               Local   p:THelpPanel = New THelpPanel
+               p.host=host
+               p.name="{{tab_help}}"
+               codeplay.addpanel(p)
+               style=HTMLVIEW_NONAVIGATE               'HTMLVIEW_NOCONTEXTMENU
+               p.htmlview=CreateHTMLView(0,0,ClientWidth(p.panel),ClientHeight(p.panel),p.panel,style)         
+               SetGadgetLayout p.htmlview,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+'              p.Home
+               p.SyncDocs
+               Return p
+       End Function
+
+End Type
+
+Type TSearchResult
+       
+       Field filepath$
+       Field char%, line%
+       Field linestring$
+       
+       Method AddToListbox( pGadget:TGadget )
+               AddGadgetItem pGadget, "[" + line + ", " + char + "] " + filepath, 0, -1, StripWhitespace(linestring,char), Self
+       EndMethod
+       
+       Method Set:TSearchResult(pFilePath$,pChar%,pLine%,pLineString$)
+               filepath = pFilePath
+               char = pChar
+               line = pLine
+               linestring = pLineString
+               Return Self
+       EndMethod
+       
+       Function StripWhitespace$(pString$,pChar%)
+               If pString.length < pChar Then Return pString
+               Local outString$
+               For Local i:Int = 0 Until pString.length
+                       Select pString[i]
+                               Case Asc(" "), Asc("~t"), Asc("~n"), Asc("~r")
+                                       If outString And Not outString.EndsWith(" ") Then outString:+" "
+                               Default
+                                       outString:+pString[i..i+1]
+                       EndSelect
+               Next
+               Return outString
+       EndFunction
+       
+EndType
+
+Type TSearchRequester Extends TRequester
+       
+       Const strSearchText$ = "{{search_btn_startsearch}}", strStopSearchText$ = "{{search_btn_stopsearch}}"
+       
+       Global strFileExts$[][] = [["bmx"],filetypes.Split(","),String[](Null)]
+       
+       Field   findbox:TGadget,typebox:TGadget,pathbox:TGadget,pathbutton:TGadget,pathsubdir:TGadget,results:TGadget
+       Field lstSearchResults:TList = New TList
+       
+       Field safetyCount% = -1, safetyThreshold = 500, safetyResetCount% = 0
+       
+       Method Poll()
+               Local id:Int = EventID()
+               Local data:Int = EventData()
+               Select EventSource()
+                       Case results
+                               Select id
+                                       Case EVENT_GADGETACTION
+                                               Local tmpSearchResult:TSearchResult = TSearchResult(EventExtra())
+                                               If tmpSearchResult Then
+                                                       host.DebugSource( tmpSearchResult.filepath, tmpSearchResult.line, tmpSearchResult.char )
+                                                       'Hide()
+                                               EndIf
+                               EndSelect
+                       Case pathbutton
+                               If EventID()=EVENT_GADGETACTION
+                                       Local tmpString$ = RequestDir( LocalizeString("{{search_requestfolder_title}}"),GadgetText(pathbox))
+                                       If tmpString Then SetGadgetText(pathbox,tmpString)
+                               EndIf
+                       Case window
+                               If EventID()=EVENT_WINDOWCLOSE Then Hide()
+                       Case findbox
+                               If EventID() = EVENT_GADGETACTION Then
+                                       If GadgetText(findbox) Then EnableGadget(ok) Else DisableGadget(ok)
+                               EndIf
+                       Case ok
+                               If EventID()=EVENT_GADGETACTION
+                                       If safetyCount < 0 Then StartSearch() Else safetyCount = -2
+                               EndIf
+                       Case cancel
+                               If EventID()=EVENT_GADGETACTION Then Hide()
+               End Select
+       End Method
+       
+       Method Hide()
+               safetyCount = -2
+               Super.Hide()
+       EndMethod
+       
+       Method ShowWithPath( pPath$ )
+               If pPath Then SetGadgetText( pathbox, pPath )
+               Show()
+               ActivateGadget( findbox )
+       EndMethod
+       
+       Method StartSearch()
+               
+               PollSystem()
+               
+               Select FileType(RealPath(GadgetText(pathbox)))
+                       Case FILETYPE_NONE
+                               Notify LocalizeString("{{search_error_pathnotfound}}"),True
+                               ActivateGadget(pathbox)
+                               Return
+                       Case FILETYPE_FILE
+                               Notify LocalizeString("{{search_error_pathisfile}}"),True
+                               ActivateGadget(pathbox)
+                               Return
+               EndSelect
+               
+               If Not GadgetText(findbox) Then
+                       Notify LocalizeString("{{search_error_nosearchstring}}"),True
+                       ActivateGadget(findbox);Return
+               EndIf
+               
+               safetyResetCount = 0;safetyCount = 0
+               LocalizeGadget ok, strStopSearchText;ClearGadgetItems results
+               SearchPath( GadgetText(pathbox), strFileExts[SelectedGadgetItem(typebox)], GadgetText(findbox).ToLower(), ButtonState(pathsubdir) )
+               LocalizeGadget ok, strSearchText;safetyCount = -1
+               SetStatusText window, LocalizeString("{{search_msg_complete}}").Replace("%1",CountGadgetItems(results))
+               
+       EndMethod
+       
+       Method SearchPath(pPath$,pFileType$[],pString$,pRecurse% = True)
+               
+               pPath$ = RealPath(pPath)                                                'Make sure we are using a real path
+               
+               Local tmpSearchDir$[] = LoadDir(pPath,True)                     'Load directors contents into string array
+               If Not tmpSearchDir Then Return                                 'Return if the directory is invalid
+               tmpSearchDir.Sort()                                                     'Sort the contents alphabetically
+               
+               SetStatusText window, LocalizeString("{{search_msg_searchingdir}}").Replace("%1", pPath)                        'And let user know which directory is being searched
+               
+               Local tmpFullPath$
+               
+               For Local tmpItem$ = EachIn tmpSearchDir
+                       
+                       tmpFullPath = pPath + "/" + tmpItem
+                       
+                       Select FileType(tmpFullPath)
+                               Case FILETYPE_NONE;Continue                              'Skip item if, for whatever reason, it doesn't exist
+                               Case FILETYPE_FILE                                       'If file, then check extension and search if valid
+                                       If Not pFileType
+                                               SearchFile(tmpFullPath,pString)
+                                       Else
+                                               Local tmpExt$ = ExtractExt(tmpFullPath).ToLower$()
+                                               For Local tmpValidExt$ = EachIn pFileType
+                                                       If tmpExt = tmpValidExt Then SearchFile(tmpFullPath,pString)
+                                               Next
+                                       EndIf
+                               Case FILETYPE_DIR                                        'If folder, then we might have to search recursively
+                                       If pRecurse Then SearchPath(tmpFullPath,pFileType,pString,pRecurse)
+                       EndSelect
+                       
+                       If Not ShouldContinue() Then Return
+                       
+               Next
+               
+               PollSystem();If PeekEvent() Then host.Poll()                    'Let the system update as we could be searching a while
+               
+       EndMethod
+       
+       Method SearchFile(pPath$,pString$)
+               Local tmpText$ = CacheAndLoadText( pPath ), tmpLines$[], tmpFindPos%, tmpCharCount%, tmpLineNo%
+               Local tmpStringLength% = pString.length, tmpChunkLines$[], tmpPrevLines$
+               
+               If tmpText Then
+                       tmpLines = tmpText.Split("~n")
+                       tmpText = tmpText.ToLower()
+                       tmpFindPos = tmpText.Find(pString)
+                       While ShouldContinue() And tmpFindPos > -1
+                               tmpChunkLines = tmpText[..tmpFindPos].Split("~n")
+                               tmpPrevLines = "~n".Join(tmpChunkLines[..tmpChunkLines.length-1])
+                               tmpLineNo:+(tmpChunkLines.length)-1
+                               Local tmpSearchResult:TSearchResult = New TSearchResult.Set(pPath,tmpFindPos-tmpPrevLines.length,tmpLineNo+1,tmpLines[tmpLineNo])
+                               tmpSearchResult.AddToListbox(results);safetyCount:+1
+                               tmpCharCount:+tmpFindPos+tmpStringLength
+                               tmpText = tmpText[tmpFindPos+tmpStringLength..]
+                               tmpFindPos = tmpText.Find(pString)
+                       Wend
+               EndIf
+       EndMethod
+       
+       Method ShouldContinue()
+               If safetyCount < 0 Then Return False
+               If safetyCount >= safetyThreshold Then
+                       If Confirm( LocalizeString("{{search_safetynotification}}").Replace("%1",(safetyResetCount*safetyThreshold)+safetyCount) ) Then
+                               safetyCount = 0
+                               safetyResetCount:+1
+                       Else
+                               safetyCount = -1
+                               Return False
+                       EndIf
+               EndIf
+               Return True
+       EndMethod
+       
+       Function Create:TSearchRequester(host:TCodePlay)
+               Local   search:TSearchRequester = New TSearchRequester
+               search.initrequester(host,"{{search_window_title}}",440,280,STYLE_CANCEL|STYLE_DIVIDER|STYLE_OK|STYLE_STATUS|STYLE_RESIZABLE,strSearchText)
+               DisableGadget(search.ok)
+               
+               SetGadgetLayout(CreateLabel("{{search_label_find}}:",6,8+4,95,24,search.window),EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED,EDGE_CENTERED)
+               search.findbox=CreateTextField(103,8,ClientWidth(search.window)-(103+6),21,search.window);SetGadgetLayout(search.findbox,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED)
+               
+               
+               SetGadgetLayout(CreateLabel("{{search_label_filetypes}}:",6,42,95,24,search.window),EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED,EDGE_CENTERED)
+               search.typebox=CreateComboBox(103,38,ClientWidth(search.window)-(103+6),24,search.window);SetGadgetLayout(search.typebox,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED)
+               
+               AddGadgetItem( search.typebox, "{{search_type_bmaxfiles}}",GADGETITEM_DEFAULT|GADGETITEM_LOCALIZED,-1,"*.bmx" )
+               AddGadgetItem( search.typebox, "{{search_type_codefiles}}",GADGETITEM_LOCALIZED,-1,fileTypes )
+               AddGadgetItem( search.typebox, "{{search_type_allfiles}}",GADGETITEM_LOCALIZED,-1,"*")
+               
+               SetGadgetLayout(CreateLabel("{{search_label_searchpath}}:",6,72,95,48,search.window),1,0,1,0)
+               search.pathbox=CreateTextField(103,68,ClientWidth(search.window)-(103+6+30+6),21,search.window);SetGadgetLayout(search.pathbox,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED)
+               search.pathbutton=CreateButton("..",ClientWidth(search.window)-(34+6),65,34,26,search.window);SetGadgetLayout(search.pathbutton,EDGE_CENTERED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED)
+               SetGadgetText(search.pathbox, CurrentDir())
+               
+               search.pathsubdir=CreateButton("{{search_btn_searchsubfolders}}",103,98,ClientWidth(search.window)-(103+6),20,search.window,BUTTON_CHECKBOX);SetGadgetLayout(search.pathsubdir,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED)
+               SetButtonState(search.pathsubdir,True)
+               
+               search.results=CreateListBox(6,128,ClientWidth(search.window)-12,280-(128+6),search.window);SetGadgetLayout(search.results,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED)
+               
+               Return search
+       End Function
+End Type
+
+
+Type TProjectRequester Extends TRequester
+       Field   projects:TProjects
+       Field   listbox:TGadget
+       Field   add:TGadget
+       Field   remove:TGadget
+       Field   props:TGadget
+       Field   moveup:TGadget
+       Field   movedown:TGadget
+       Field   Current:TProjectFolderNode
+
+       Method Invoke(command,arg:Object=Null)
+               Select command
+               Case TOOLACTIVATE
+                       Refresh
+               End Select
+       End Method
+       
+       Method SetCurrent(i)
+               If i=-1
+                       DisableGadget remove
+                       DisableGadget moveup
+                       DisableGadget movedown
+                       DisableGadget props
+                       Current=Null
+               Else
+                       Current=TProjectFolderNode(GadgetItemExtra(listbox,i))
+                       If Current
+                               EnableGadget remove
+                               EnableGadget props
+                               EnableGadget moveup
+                               EnableGadget movedown
+                       EndIf
+               EndIf
+       End Method
+
+       Method Poll()
+               Local   index
+               Select EventSource()
+                       Case window
+                               If EventID()=EVENT_WINDOWCLOSE Then Hide()
+                       Case add
+                               If EventID() = EVENT_GADGETACTION Then
+                                       projects.NewProject
+                                       Refresh
+                               EndIf
+                       Case remove
+                               If EventID() = EVENT_GADGETACTION Then
+                                       projects.RemoveProject SelectedGadgetItem(listbox)
+                                       Refresh
+                               EndIf
+                       Case cancel
+                               If EventID() = EVENT_GADGETACTION Then Hide
+                       Case props
+                               If EventID() = EVENT_GADGETACTION And Current
+                                       host.projectprops.Open(Current)
+                               EndIf
+                       Case listbox
+                               If EventID()=EVENT_GADGETSELECT
+                                       SetCurrent SelectedGadgetItem(listbox)  'EventData()
+                               ElseIf EventID()=EVENT_GADGETACTION
+                                       SetCurrent SelectedGadgetItem(listbox)
+                                       host.projectprops.Open(Current)
+                               EndIf
+                       Case moveup
+                               If EventID()=EVENT_GADGETACTION Then
+                                       index=projects.MoveProject(SelectedGadgetItem(listbox),-1)
+                                       Refresh
+                                       SelectGadgetItem listbox,index
+                                       SetCurrent(index)
+                               EndIf
+                       Case movedown
+                               If EventID()=EVENT_GADGETACTION Then
+                                       index=projects.MoveProject(SelectedGadgetItem(listbox),1)
+                                       Refresh
+                                       SelectGadgetItem listbox,index
+                                       SetCurrent(index)
+                               EndIf
+               End Select
+       End Method
+
+       Method Refresh()
+               ClearGadgetItems listbox
+               For Local node:TNode = EachIn projects.kids
+                       If TFolderNode(node)'node.argument
+                               AddGadgetItem listbox,node.name,0,-1,"",node
+                       EndIf
+               Next
+               SetCurrent -1
+       End Method
+       
+       Method Open(projnode:TProjects)
+               projects=projnode
+               Refresh
+               Show
+       End Method
+       
+       Function Create:TProjectRequester(host:TCodePlay)
+               Local x,y
+               Local   proj:TProjectRequester = New TProjectRequester
+       
+               proj.initrequester(host,"{{projman_window_title}}",400,168,STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL)
+               proj.listbox=CreateListBox( 6,8,244,154,proj.window )
+               
+               x=ClientWidth(proj.window)-144
+               proj.add=CreateButton("{{projman_btn_addproj}}",x,8,138,26,proj.window)
+               proj.remove=CreateButton("{{projman_btn_delproj}}",x,40,138,26,proj.window)
+
+               proj.moveup=CreateButton("{{projman_btn_moveup}}",x,72,138,26,proj.window)
+               proj.movedown=CreateButton("{{projman_btn_movedn}}",x,104,138,26,proj.window)
+
+               proj.props=CreateButton("{{projman_btn_properties}}",x,136,138,26,proj.window)
+
+               DisableGadget proj.remove
+               DisableGadget proj.moveup
+               DisableGadget proj.movedown
+               DisableGadget proj.props
+               Return proj
+       End Function
+End Type
+
+Type TProjectProperties Extends TRequester
+       Field proj:TProjectFolderNode
+       Field newproj:Int = False                               'If 'True' then cancel/close deletes project.
+       Field localname:TGadget
+       Field localpath:TGadget
+       Field pathbutton:TGadget
+       Field path:TGadget
+       Field user:TGadget
+       Field password:TGadget
+       Field checkout:TGadget
+'      Field update:TGadget
+'      Field commit:TGadget
+       Field poprequester:TRequester   'hack for restoring to projectmanager requester
+       Field dirty
+
+       Method Invoke(command,arg:Object=Null)
+               Select command
+               Case TOOLACTIVATE
+                       Refresh
+               End Select
+       End Method
+       
+       Method Tidy()
+               newproj = False
+               If dirty
+                       proj.Set GadgetText(localname),GadgetText(localpath),GadgetText(path),GadgetText(user),GadgetText(password)
+                       dirty=False
+               EndIf
+       End Method
+       
+       Method Poll()
+               If (EventID() <> EVENT_GADGETACTION) And (EventID() <> EVENT_WINDOWCLOSE) Then Return
+               Select EventSource()
+                       Case localname,localpath,path,user,password
+                               dirty=True
+                       Case pathbutton
+                               Local dir$=RequestDir(LocalizeString("{{project_requestfolder_title}}"))
+                               If dir
+                                       If dir[dir.length-1..]="/"      'fltk hack
+                                               dir=dir[..dir.length-1]
+                                       EndIf
+                                       SetGadgetText localpath,dir
+                                       If GadgetText(localname)=""
+                                               SetGadgetText localname,StripDir(dir)
+                                       EndIf
+                                       dirty=True
+                               EndIf                           
+                       Case checkout
+                               Tidy()
+                               Hide()
+                               proj.CheckoutVersion()
+Rem
+                       Case commit
+                               Tidy
+                               Hide                            
+                               proj.CommitVersion              
+                       Case update
+                               Tidy
+                               Hide                            
+                               proj.UpdateVersion              
+EndRem
+                       Case ok
+                               Tidy()
+                               Hide()
+                       Case cancel
+                               Hide()
+                       Case window
+                               If EventID()=EVENT_WINDOWCLOSE
+                                       Hide()
+                               EndIf
+               End Select
+       End Method
+       
+       Method Hide()
+               If proj And newproj Then proj.Free()
+               EnableGadget host.window
+               HideGadget window
+               host.UnhookRequester Self'poprequester
+               If poprequester poprequester.Show
+       End Method
+
+       Method Refresh()
+               SetGadgetText localname,proj.name
+               SetGadgetText localpath,proj.path
+               SetGadgetText path,proj.svnpath
+               SetGadgetText user,proj.svnuser
+               SetGadgetText password,proj.svnpass
+       End Method
+       
+       Method Open(projnode:TProjectFolderNode, newproject:Int = False)
+               newproj=newproject
+               proj=projnode
+               Refresh()
+               Show()
+       End Method
+       
+       Function Create:TProjectProperties(host:TCodePlay)
+               Local   proj:TProjectProperties = New TProjectProperties
+               proj.initrequester(host,"{{project_window_title}}",480,250,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL)
+               proj.modal = True
+               
+               Local projectdetails:TGadget = CreatePanel(6,8,ClientWidth(proj.window)-12,85,proj.window,PANEL_GROUP,"{{project_group_details}}")
+               
+               Local i,n,y
+               y=4
+
+               CreateLabel("{{project_label_name}}:",6,y+4,72,24,projectdetails)
+               proj.localname=CreateTextField(88,y,ClientWidth(projectdetails)-(88+6),21,projectdetails)
+'              proj.pathbutton=CreateButton("..",434,y,34,28,projectdetails)
+               y:+30
+
+               CreateLabel("{{project_label_path}}:",8,y+4,72,24,projectdetails)
+               proj.localpath=CreateTextField(88,y,ClientWidth(projectdetails)-(88+34+6+6),21,projectdetails)
+               proj.pathbutton=CreateButton("..",ClientWidth(projectdetails)-(34+6),y-3,34,26,projectdetails)
+               y:+30
+
+
+               Local svnbox:TGadget = CreatePanel(6,101,ClientWidth(proj.window)-12,144,proj.window,PANEL_GROUP,"{{project_group_svn}}")
+               y=4
+               CreateLabel("{{project_label_url}}:",8,y+LABELOFFSET,72,24,svnbox)
+               proj.path=CreateTextField(88,y,ClientWidth(svnbox)-92,21,svnbox)
+               y:+30
+               CreateLabel("{{project_label_username}}:",8,y+LABELOFFSET,72,24,svnbox)
+               proj.user=CreateTextField(88,y,ClientWidth(svnbox)-92,21,svnbox)
+               y:+30
+               CreateLabel("{{project_label_password}}:",8,y+LABELOFFSET,72,24,svnbox)
+               proj.password=CreateTextField(88,y,ClientWidth(svnbox)-92,21,svnbox,TEXTFIELD_PASSWORD)         
+               y:+30
+               proj.checkout=CreateButton("{{project_btn_checkout}}",ClientWidth(svnbox)-154,ClientHeight(svnbox)-32,150,28,svnbox)
+'              proj.update=CreateButton("{{project_btn_update}}",180,y+10,150,28,svnbox)
+'              proj.commit=CreateButton("{{project_btn_commit}}",340,y+10,150,28,svnbox)
+               y:+40
+
+               Return proj
+       End Function
+End Type
+
+Function GetInfo$(a$ Var)
+       Local p,r$
+       p=a.Find("|")+1
+       If p=0 p=a.length+1
+       r$=a$[..p-1]
+       a$=a$[p..]
+       Return r$       
+End Function
+
+Type TFolderNode Extends TNode
+       Field   owner:TNode
+       Field   path$
+       Field   scanned
+       Field   version
+       Field   foldertype
+       
+       Const PROJECTFOLDER=0
+       Const DIRECTORYFOLDER=1
+       Const FILEFOLDER=2
+
+       Method FindFolderFromPath:TFolderNode(dir$)
+               Local result:TFolderNode
+               If path=dir Return Self
+               For Local folder:TFolderNode = EachIn kids
+                       result=folder.FindFolderFromPath(dir)
+                       If result Return result
+               Next
+       End Method
+       
+       Method SetName(n$)
+               If version Then n:+"("+version+")"
+               Super.SetName( n )
+               Refresh
+       End Method
+               
+       Method SetVersion(ver)
+               version=ver
+               SetName StripDir(path)
+       End Method
+       
+       Method Write(stream:TStream)
+               Local isopen
+               If GetState()=OPENSTATE isopen=True
+               If version Or isopen
+                       stream.WriteLine "proj_data="+path+"|"+isopen+"|"+version+"|"
+               EndIf
+               For Local folder:TFolderNode = EachIn kids
+                       folder.Write(stream)
+               Next
+       End Method
+
+       Method ProjectHost:TCodePlay()
+               Local n:TNode = Self
+               While n
+                       If TProjects(n) Return TProjects(n).host
+                       n=n.parent
+               Wend
+       End Method
+
+       Method ProjectNode:TProjectFolderNode()
+               Local n:TNode = Self
+               While n
+                       If TProjectFolderNode(n) Return TProjectFolderNode(n)
+                       n=n.parent
+               Wend
+       End Method
+
+       Method RunSVN(cmd$,about$,refresh)
+       
+               Local host:TCodePlay = ProjectHost()
+               If Not host Notify LocalizeString("{{svn_notification_nodehostnotfound}}");Return
+               
+               Local project:TProjectFolderNode = ProjectNode()
+               If Not project Notify LocalizeString("{{svn_notification_nodeprojectnotfound}}");Return
+               
+               If project.svnuser
+                       cmd:+" --username "+project.svnuser
+                       If project.svnpass cmd:+" --password "+project.svnpass
+               EndIf
+
+               If refresh
+                       host.execute cmd,about,MENUREFRESH,True,Self
+               Else
+                       host.execute cmd,about,0,0,Self
+               EndIf
+       End Method
+       
+       Method UpdateVersion()
+               Local cmd$=svncmd+" update"
+               cmd:+" "+quote(path)
+               RunSVN cmd,LocalizeString("{{svn_msg_updating}}").Replace("%1",path),True
+       End Method
+       
+       Method CommitVersion()
+               Local cmd$=svncmd+" commit"
+               cmd:+" -m ~qmy comment~q"
+               cmd:+" "+quote(path)
+               RunSVN cmd,LocalizeString("{{svn_msg_committing}}").Replace("%1",path),False
+       End Method
+       
+       Method Open(view=-1)
+               Update(True)
+               Super.Open view
+       End Method
+
+       Method AddFileNode:TNode(file$)
+               Local   n:TNode
+               Local ext$      
+               If (","+FileTypes+",").Contains(","+ExtractExt(file).toLower()+",") Then
+                       n=AddNode(StripDir(file))
+                       n.SetAction(owner,TOOLOPEN,file)
+                       ext=ExtractExt(file$).ToLower()
+                       n.sortname=ext+n.name
+                       Return n
+               EndIf
+       End Method
+
+       Method AddFolderNode:TNode(path$)
+               Local   n:TFolderNode = TFolderNode.CreateFolderNode(path,DIRECTORYFOLDER)
+               n.owner = owner
+               n.sortname=" "+n.name
+               Append n
+               Return n
+       End Method
+
+       Method Scan(o:TNode)
+               Local p$
+               Local flist:TList = New TList
+               
+               owner=o
+               
+               For Local f$ = EachIn LoadDir(path,True)
+                       If f[..1] = "." Then Continue
+                       p$=path+"/"+f
+                       Select FileType(p$)
+                               Case FILETYPE_FILE
+                                       AddFileNode p$
+                               Case FILETYPE_DIR
+                                       AddFolderNode p$
+                       End Select      
+               Next
+               
+               SortKids
+               scanned = True
+               
+       End Method
+       
+       Method ScanKids()
+               For Local f:TFolderNode = EachIn kids
+                       f.owner = owner
+                       f.Update(False)
+               Next
+       End Method
+       
+       Method Rescan()
+               scanned = False
+               Update()
+       EndMethod
+       
+       Method Update( alwaysScanKids:Int = False )
+               If Not scanned Then
+                       FreeKids()
+                       Scan owner
+               EndIf
+               If alwaysScanKids Or Not IsHidden() Then ScanKids()
+               Refresh()
+       End Method
+       
+       Method Invoke(command,argument:Object=Null)
+               Local host:TCodePlay
+               Local cmd,p
+               Local line$
+       
+               host=ProjectHost()
+               If Not host Notify LocalizeString("{{svn_notification_nodehostnotfound}}");Return
+               
+               Select command
+               Case TOOLOUTPUT
+                       line$=String(argument)
+                       p=line.find(" revision ")
+                       If p>-1
+                               SetVersion Int(line[p+10..])
+                       EndIf
+'                      If line[..12]="At revision "
+'                      DebugLog "TOOLOUTPUT:"+line
+                       Return
+               Case TOOLERROR
+                       line$=String(argument)
+'                      DebugLog "TOOLERROR:"+line
+                       Return
+               Case TOOLMENU
+                       cmd=Int(String(argument))
+                       Select cmd
+                       Case 0          'special toolmenu-command=0 fired by rightbutton node context
+                               Highlight                       
+                               Local menu:TGadget
+                               menu=host.projects.projmenu
+                               PopupWindowMenu host.window,menu,Self
+                       Case MENUREFRESH
+                               Rescan()
+                       Case MENUBROWSE
+                               OpenURL RealPath(path)
+                       Case MENUSHELL
+                               Local cd$=CurrentDir()
+                               ChangeDir RealPath(path)
+?MacOS
+                               host.execute "/bin/bash","Shell Terminal"
+?Linux
+                               host.execute "/bin/bash","Shell Terminal"
+?Win32
+                               host.execute "cmd","Shell Terminal - Type Exit To End"
+?
+                               ChangeDir cd
+                       Case MENUUPDATE
+                               UpdateVersion
+                       Case MENUCOMMIT
+                               CommitVersion
+'                      Case MENUPROPS
+'                              host.projectprops.Open(Self)
+                       Case MENUFINDINFILES
+                               host.searchreq.ShowWithPath( RealPath(path) )
+                       End Select
+               End Select
+       End Method
+
+       Function CreateFolderNode:TFolderNode(path$,foldertype)
+               Local   n:TFolderNode = New TFolderNode
+'              n.host=host
+               n.SetName( StripDir(path) )
+               n.path = path
+               n.foldertype = foldertype
+               Return n
+       End Function
+End Type
+
+Type TProjectFolderNode Extends TFolderNode
+       
+       Field owner:TProjects
+       Field svnpath$,svnuser$,svnpass$,svnversion
+       Field svnerr$
+
+       Method CheckoutVersion()        'to do - needs to move old version to temp?
+               Local cmd$ = svncmd+" checkout"
+               cmd:+" "+quote(svnpath)
+               cmd:+" "+quote(path)
+               RunSVN cmd,LocalizeString("{{svn_msg_checkingout}}").Replace("%1",svnpath).Replace("%2",path),True
+       End Method
+
+       Function Crypt$(a$)
+               Local b$,c
+               For Local i:Int = 0 Until a.length
+                       c=a[i]
+                       If c>31 c:~((i*-5)&31)
+                       b:+Chr(c&255)
+               Next
+               Return b
+       End Function
+
+       Method ToString$()
+               Local prj$
+               Local isopen
+               If GetState()&OPENSTATE isopen=True
+               prj=name+"|"+path+"|"+svnpath+"|"+svnuser+"|"+crypt(svnpass)+"|"+isopen+"|"+version
+               Return prj
+       End Method
+
+       Method Write(stream:TStream)
+               stream.WriteLine "proj_node="+ToString()
+               For Local folder:TFolderNode = EachIn kids
+                       folder.Write(stream)
+               Next
+       End Method
+       
+       Method FromString(info$)
+               Local n$ = GetInfo(info)
+               If Not n Then n = "Unknown"
+               SetName( n )
+               path=GetInfo(info)
+               If path path=owner.host.FullPath(path)
+               svnpath=GetInfo(info)
+               svnuser=GetInfo(info)
+               svnpass=GetInfo(info)
+               Scan(owner)
+               Local isopen,vers
+               isopen=Int(GetInfo(info))
+               If isopen
+                       Open
+               EndIf   
+               vers=Int(GetInfo(info))
+               If vers
+                       SetVersion vers
+               EndIf
+       End Method
+
+       Method Invoke(command,argument:Object=Null)
+               Local cmd
+               Select command
+               Case TOOLMENU
+                       cmd=Int(String(argument))
+                       Select cmd
+                       Case MENUPROPS
+                               Return owner.host.projectprops.Open(Self)
+                       End Select
+               End Select
+               Return Super.Invoke(command,argument)
+       End Method
+
+       Method Set(n$,p$,s$,user$,pass$)
+               path=owner.host.FullPath(p)
+               setname n
+               svnpath=s
+               svnuser=user
+               svnpass=pass
+               Rescan()
+               owner.host.projectreq.Refresh()
+       End Method
+
+       Function CreateProjectNode:TProjectFolderNode(projects:TProjects,info$)
+               Local n:TProjectFolderNode = New TProjectFolderNode
+               n.owner=projects
+               n.FromString(info)
+               n.foldertype=PROJECTFOLDER
+               Return n
+       End Function
+End Type
+
+Type TProjects Extends TNode
+       Field host:TCodePlay
+       Field addproj:TNode
+       Field projmenu:TGadget
+       Field projmenuprops:TGadget
+
+       Method RemoveProject(index)
+               Local   node:TNode
+               If index<0 Or index>=kids.Count() Return
+               node=TNode(kids.ValueAtIndex(index))
+               If node node.Free
+               Refresh
+       End Method                      
+       
+       Method MoveProject(index,dir)
+               Local node:TNode
+               Local link:TLink
+               If index<0 Or index>=kids.Count() Return index
+               node=TNode(kids.ValueAtIndex(index))
+               If node
+                       addproj.Detach
+                       node.Hide
+                       link=kids.FindLink(node)
+                       If dir>0
+                               If link link=link._succ
+                               If link
+                                       kids.Remove node
+                                       kids.InsertAfterLink node,link
+                                       index:+1
+                               EndIf
+                       Else
+                               If link link=link._pred
+                               If link
+                                       kids.Remove node
+                                       kids.InsertBeforeLink node,link                 
+                                       index:-1
+                               EndIf
+                       EndIf           
+                       Append addproj
+                       Refresh
+               EndIf
+               Return index
+       End Method                      
+
+       Method NewProject()
+               addproj.Detach
+               Local proj:TProjectFolderNode = TProjectFolderNode.CreateProjectNode(Self,LocalizeString("{{project_defaultname}}"))
+'              proj.scan(Self)
+               Append proj
+               Append addproj
+               host.projectprops.Open(proj, True)
+               Refresh
+       End Method
+
+       Method AddProject(data:TList)
+               Local project:TProjectFolderNode
+               Local folder:TFolderNode
+               For Local info$ = EachIn data
+                       If Not project
+                               addproj.Detach
+                               project=TProjectFolderNode.CreateProjectNode(Self,info)
+                               Append project
+                               Append addproj
+                               Refresh
+                       Else
+                               Local path$
+                               Local popen
+                               Local pversion
+                               path=GetInfo(info)
+                               popen=Int(GetInfo(info))
+                               pversion=Int(GetInfo(info))
+                               folder=project.FindFolderFromPath(path)
+                               If folder
+                                       folder.SetVersion pversion
+                                       folder.ReScan()
+                                       If popen Then folder.Open()
+                               EndIf           
+                       EndIf
+               Next
+       End Method
+
+       Method Write(stream:TStream)
+               For Local project:TProjectFolderNode = EachIn kids
+                       project.Write(stream)           
+               Next
+       End Method
+
+       Method Invoke(command,argument:Object=Null)
+               Select command
+               Case TOOLNEW
+                       NewProject
+               Case TOOLOPEN
+                       host.OpenSource String(argument)
+               End Select
+       End Method
+                       
+       Function CreateProjects:TProjects(host:TCodePlay)
+               Local p:TProjects = New TProjects
+               p.SetName("{{navnode_projects}}")
+               p.host=host             
+               p.addproj=p.AddNode("{{navnode_addproject}}")
+               p.addproj.SetAction p,TOOLNEW
+
+               p.projmenu=CreateMenu("{{popup_nav_proj}}",0,Null)
+               CreateMenu "{{popup_nav_proj_refresh}}",MENUREFRESH,p.projmenu
+               CreateMenu "{{popup_nav_proj_findinfiles}}",MENUFINDINFILES,p.projmenu
+               CreateMenu "{{popup_nav_proj_explore}}",MENUBROWSE,p.projmenu
+               CreateMenu "{{popup_nav_proj_shell}}",MENUSHELL,p.projmenu
+               CreateMenu "",0,p.projmenu
+               CreateMenu "{{popup_nav_proj_svnupdate}}",MENUUPDATE,p.projmenu
+               CreateMenu "{{popup_nav_proj_svncommit}}",MENUCOMMIT,p.projmenu
+               CreateMenu "",0,p.projmenu
+               p.projmenuprops=CreateMenu("{{popup_nav_proj_properties}}",MENUPROPS,p.projmenu)
+               host.projectreq.projects=p
+               Return p
+       End Function
+End Type
+
+Type TByteBuffer Extends TStream
+       Field   bytes:Byte[]
+       Field   readpointer
+
+       Method Read( buf:Byte Ptr,count )
+               If count>readpointer count=readpointer
+               If Not count Return
+               MemCopy buf,bytes,count
+               readpointer:-count
+               If readpointer MemMove bytes,Varptr bytes[count],readpointer
+               Return count
+       End Method
+       
+       Method ReadLine$()
+               For Local i:Int = 0 Until readpointer
+                       If bytes[i]=10 Or bytes[i] = 0 Then
+                               Local tmpBytes:Byte[] = New Byte[i+1]
+                               If i And bytes[i-1] = 13 Then i:-1
+                               Read(tmpBytes,tmpBytes.length)
+                               Return String.FromBytes(tmpBytes, i)
+                       EndIf
+               Next
+       EndMethod
+       
+       Method WriteFromPipe( pipe:TPipeStream )
+               Local   n,m,count = pipe.ReadAvail()
+               n=readpointer+count
+               If n>bytes.length
+                       m=Max(bytes.length*1.5,n)
+                       bytes=bytes[..m]
+               EndIf
+               pipe.Read( Varptr bytes[readpointer], count )
+               readpointer=n
+               Return count
+       EndMethod
+       
+       Method Write( buf:Byte Ptr,count )
+               Local   n,m
+               n=readpointer+count
+               If n>bytes.length
+                       m=Max(bytes.length*1.5,n)
+                       bytes=bytes[..m]
+               EndIf
+               MemCopy Varptr bytes[readpointer],buf,count
+               readpointer=n
+               Return count
+       End Method      
+       
+       Method LineAvail()
+               For Local i:Int = 0 Until readpointer
+                       If bytes[i]=10 Return True
+               Next
+       End Method
+
+       Method FlushBytes:Byte[]()
+               Local res:Byte[] = bytes[..readpointer]
+               readpointer = 0
+               Return res
+       End Method
+End Type
+
+Type TObj
+       Field   addr$,sync,refs,syncnext
+       Method ShouldSync( pDebugTree:TDebugTree )
+               If sync < pDebugTree.sync Then pDebugTree.QueueSync( Self )
+       EndMethod
+       Method HasSynced( pSync% )
+               sync = pSync;syncnext = False
+       EndMethod
+End Type
+
+Type TVar Extends TNode
+
+       Field   owner:TDebugTree
+       Field   obj:Object
+
+       Method Free()
+               If TObj(obj) owner.RemoveObj TObj(obj)
+               obj=Null
+               Super.Free()
+       End Method
+
+       Method SetVarName(n$)
+               Local   p
+               name=n
+' if object ref set addr$ field        
+               If name.find("$=")=-1 And name.find( ":String=" )=-1 And name.find(")=$")=-1
+                       p=name.find("=$")
+                       If p<>-1
+                               If TObj(obj) Then
+                                       If TObj(obj).addr <> name[p+2..] Then
+                                               TDebugTree.RemoveObj TObj(obj)
+                                       Else
+                                               TObj(obj).refs:-1
+                                       EndIf   
+                               EndIf                           
+                               obj=TDebugTree.AddObj(name[p+2..])
+                               'Request object dump if we are visible now that
+                               'we have updated our own object pointer.
+                               If Not IsHidden() Then Request()
+                               Return
+                       EndIf
+                       p=name.find("=Null")
+                       If p<>-1
+                               FreeKids
+                               TDebugTree.RemoveObj TObj(obj)
+                               obj=Null
+                       EndIf
+               EndIf
+       End Method
+       
+       Method AddVar(name$)
+               Local   v:TVar=New TVar
+               v.owner=owner
+               Append v
+               v.setvarname name
+       End Method
+       
+       Method SetValue(val:TVar)
+               Local   v:TVar,w:TVar,i,kidsarray:Object[]
+' if this is a reference to same object refresh values
+               If obj And obj=val.obj
+                       If kids.IsEmpty()
+                               For v=EachIn val.kids
+                                       AddVar v.name
+                               Next
+                       Else
+                               kidsarray = kids.ToArray()
+                               For v=EachIn val.kids
+                                       If i<kidsarray.length
+                                               w=TVar(kidsarray[i])
+                                               If w w.SetVarName v.name
+                                       Else
+                                               AddVar v.name
+                                       EndIf
+                                       i:+1
+                               Next
+                               kidsarray = Null        
+                       EndIf
+                       Refresh
+               EndIf   
+' recurse so all references are updated
+               If IsHidden() Then Return                               'parent And parent.state=CLOSEDSTATE Return
+               For v=EachIn kids
+                       v.SetValue val
+               Next
+       End Method
+       
+       Method Open(open=-1)
+               For Local kid:TVar = EachIn kids
+                       kid.Request()
+               Next
+               Super.Open(open)
+       EndMethod
+       
+       Method Request()
+               If TObj(obj) Then TObj(obj).ShouldSync(owner)
+       EndMethod
+       
+End Type
+
+Type TScope Extends TVar
+       Field   tree:TDebugTree
+       Field   file$,line,column
+
+       Method Invoke(command,argument:Object=Null)
+               Select command
+                       Case TOOLACTIVATE
+                               tree.SelectScope Self,True
+               End Select
+       End Method
+       
+       Method SetScope(s:TScope)
+               Local   v:TVar
+               file=s.file
+               line=s.line
+               column=s.column
+               s.obj=Self
+               SetValue s
+       End Method
+       
+       Method SetFile(debugtree:TDebugTree,f$)
+               tree=debugtree
+               Local p=f.Find("<")+1
+               Local q=f.Find(">")+1
+               Local r=f.Find(",")+1
+               If p And q And r
+                       file=f[..p-1]
+                       line=Int(f[p..r-1])
+                       column=Int(f[r..q-1])
+               EndIf
+               obj=Self
+       End Method
+       
+       Method Request()
+               For Local kid:TVar = EachIn kids
+                       kid.Request()
+               Next
+       EndMethod
+       
+End Type
+
+Type TDebugTree Extends TVar
+       Global  sync
+       Global  objmap:TMap = CreateMap()
+       Field   host:TCodePlay
+       Field   instack:TList
+       Field   inscope:TScope
+       Field   invar:TVar
+       Field   infile$
+       Field   inexception$
+       Field   firststop
+       Field   cancontinue
+       
+       Method Reset()
+'              host.SetMode host.DEBUGMODE
+               SetStack( New TList )
+               ClearMap objmap
+               instack=Null
+               inscope=Null
+               invar=Null
+               infile=""
+               inexception=""
+               sync=0
+               firststop=True
+               cancontinue=False
+       End Method
+
+       Function AddObj:TObj(addr$)
+               Local   o:TObj = TObj(MapValueForKey( objmap, addr ))
+               If o Then
+                       o.refs:+1
+               Else
+                       o=New TObj
+                       o.addr=addr
+                       o.refs=1
+                       MapInsert objmap, addr, o
+               EndIf
+               Return o
+       End Function
+
+       Function FindObj:TObj(addr$)
+               Return TObj(MapValueForKey( objmap, addr ))
+       End Function
+       
+       Function RemoveObj(obj:TObj)            ':TObj
+               If obj Then
+                       obj.refs:-1
+                       If Not obj.refs Then MapRemove objmap, obj.addr
+               EndIf
+       End Function
+
+       Method SyncVars()
+               sync:+1
+               For Local tmpVar:TVar = EachIn kids
+                       tmpVar.Request()
+               Next
+       End Method
+       
+       Method QueueSync( pObj:TObj )
+               If Not pObj Then Return
+               'Sync as soon as the debug pipe is clear
+               '(see TOuputPanel.SendDumpRequests()).
+               pObj.syncnext = True
+       EndMethod
+                       
+       Method SetStack(list:TList)
+               Local   openscope:TScope
+               Local   s:TScope
+               Local   count,i
+
+               count=kids.count()                      'root.varlist.count()
+               For Local scope:TScope = EachIn list
+                       If i>=count
+                               Append scope            'root.Append scope
+                               s=scope
+                       Else
+                               s=TScope(kids.ValueAtIndex(i))
+' simon was here                               
+                               If s.name=scope.name
+                                       s.SetScope scope
+                                       scope.Free
+                               Else
+                                       While kids.count()>i
+                                               s=TScope(kids.Last())
+                                               s.free
+                                       Wend
+                                       Append scope
+                                       s=scope
+                                       count=i+1
+                               EndIf
+                               
+                       EndIf
+                       If firststop
+                               If host.IsSourceOpen(s.file) openscope=s
+                       Else
+                               openscope=s
+                       EndIf
+                       i:+1
+               Next
+               While kids.count()>i
+                       s=TScope(kids.Last())
+                       s.free
+               Wend
+               If list.IsEmpty() Return
+               If Not openscope openscope=TScope(list.First())
+               If openscope SelectScope openscope,True
+               Refresh
+               firststop=False
+       End Method
+
+       Method SelectScope(scope:TScope,open)
+               If Not scope Return             
+               host.SetMode host.DEBUGMODE     ' simon was here, smoved from reset
+               If scope.file host.DebugSource scope.file,scope.line,scope.column
+               scope.Open()
+'              If open
+'                      SelectTreeViewNode scope.node
+'                      scope.open
+'              EndIf
+       End Method
+
+       Method ProcessError$(line$)
+               Local   p
+               
+               While p < line.length
+                       If line[p]=$3E Then p:+1 Else Exit              '">"
+               Wend
+               
+               If p = line.length Return
+               If p Then line = line[p..]
+
+               If Not line.StartsWith("~~>") Return line
+               line=line[2..]
+
+               If invar
+                       If line="}"
+                               SetValue invar          'root
+                               invar.Free
+                               invar=Null
+                       Else
+'                              If Not invar.name
+'                                      invar.name=line
+'                              Else
+                                       invar.AddVar line
+'                              EndIf
+                       EndIf
+                       Return
+               EndIf
+               
+               If instack                      
+                       If line="}"
+                               
+                               SetStack instack
+                               instack=Null
+                               inscope=Null
+                               'Request first object dumps, and bump sync count
+                               SyncVars
+                               If inexception
+                                       Notify inexception
+                                       inexception=""
+                               EndIf
+                               Return
+                       EndIf
+                       
+                       If infile
+                               If line="Local <local>"
+                               Else
+                                       inscope=New TScope
+'                                      Print "inscope.line="+line
+                                       inscope.name=line
+                                       inscope.owner=Self
+                                       instack.AddLast inscope
+                               EndIf
+                               If inscope inscope.setfile Self,infile
+                               infile=""
+                               Return
+                       EndIf
+
+                       If line.StartsWith("@") And line.Contains("<")
+                               infile=line[1..]
+                       Else
+                               If inscope inscope.AddVar line
+                       EndIf
+
+                       Return
+               EndIf
+
+               If line.StartsWith("Unhandled Exception:")
+                       inexception=line
+                       host.output.WritePipe "t"
+                       cancontinue=False
+                       Return
+               EndIf
+
+               If line="StackTrace{"
+                       instack=New TList
+                       Return
+               EndIf
+
+               If line="Debug:" Or line="DebugStop:"
+                       host.output.WritePipe "t"
+                       If Not cancontinue Then
+                               cancontinue=True
+                               host.RefreshToolbar()
+                       EndIf
+                       Return
+               EndIf                                   
+               
+               If line.StartsWith("ObjectDump@")
+                       p=line.find("{",11)
+                       If p=-1 Return line
+                       line=line[11..p]
+                       invar=New TVar
+                       invar.obj=FindObj(line)
+                       invar.owner=Self
+                       Return
+               EndIf
+               
+       End Method
+
+       Function CreateDebugTree:TDebugTree(host:TCodePlay)
+               Local   d:TDebugTree = New TDebugTree
+               d.owner=d
+               d.SetName "{{navtab_debug}}"
+               d.host=host
+               d.Open
+               Return d                
+       End Function
+End Type
+
+Type TNodeView
+       Field   owner:TNavBar
+       Field   root:TNode
+       Field   treeview:TGadget
+       Field   index
+       
+       Method NewView()
+               Local   n:TNode,hnode:TGadget
+               hnode=SelectedTreeViewNode(treeview)
+               n=root.Find(hnode,index)
+               If n And n.parent owner.AddView n
+       End Method
+
+       Method OnEvent()
+               Local   n:TNode = root.Find(TGadget(EventExtra()),index)
+               If Not n Return 'probably an eventgadgetselect -1 Notify("could not find in root");Return
+
+               Select EventID()
+                       Case EVENT_GADGETSELECT
+                               n.invoke(TOOLSELECT)                            
+                       Case EVENT_GADGETACTION
+                               n.invoke(TOOLACTIVATE)                          
+                       Case EVENT_GADGETMENU
+                               n.invoke(TOOLMENU,Self)
+                       Case EVENT_GADGETOPEN
+                               n.open index
+                       Case EVENT_GADGETCLOSE
+                               n.close index
+               End Select
+       End Method
+End Type
+
+Type TNavBar Extends TEventHandler
+       Field   host:TCodePlay
+       Field   tabber:TGadget
+       Field   viewlist:TList=New TList
+       Field   selected:TNodeView
+       Field   navmenu:TGadget
+       
+       Method SelectedView()
+               If selected Return selected.index
+       End Method
+               
+       Method SelectView(index)
+               Local   n:TNodeView
+               If index>=viewlist.count() Return
+               n=TNodeView(viewlist.ValueAtIndex(index))
+               If Not n Print "selectview failed";Return
+               If n<>selected
+                       If selected HideGadget selected.treeview
+                       selected=n
+               EndIf
+               ShowGadget n.treeview
+               SelectGadgetItem tabber,index
+       End Method
+       
+       Method AddView(node:TNode)
+               Local   n:TNodeView
+               Local   index,root:TGadget
+               For n=EachIn viewlist
+                       If n.root=node SelectView n.index;Return
+               Next
+               n=New TNodeView
+               n.owner=Self
+               n.root=node
+               n.treeview=CreateTreeView(0,0,ClientWidth(tabber),ClientHeight(tabber),tabber)
+               host.options.navstyle.Apply n.treeview
+               SetGadgetLayout n.treeview,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+               HideGadget n.treeview
+
+               n.index=viewlist.Count()
+               viewlist.AddLast n              
+               
+               AddGadgetItem tabber,node.name,GADGETITEM_LOCALIZED
+               root=TreeViewRoot(n.treeview)
+               node.setnode root,n.index
+               SelectView n.index
+               Return n.index
+       End Method
+
+       Method OnEvent()
+               If EventSource()=tabber
+                       SelectView SelectedGadgetItem(tabber)                           
+               End If
+               If selected And EventSource()=selected.treeview
+                       selected.OnEvent
+               EndIf
+       End Method
+
+       Method Refresh()
+               For Local view:TNodeView = EachIn viewlist
+                       host.options.navstyle.Apply view.treeview
+               Next
+       End Method
+
+       Method Invoke(command,argument:Object=Null)
+               If command=TOOLREFRESH Refresh()                
+               If command=TOOLNEWVIEW And selected selected.NewView
+       End Method
+
+       Function CreateNavMenu:TGadget()
+               Local   edit:TGadget = CreateMenu("&Nav",0,Null)
+               CreateMenu "&New View",MENUNEWVIEW,edit
+               Return edit
+       End Function
+
+       Function Create:TNavBar(host:TCodePlay, parent:TGadget) ',root:TNode)
+               Local   n:TNavBar = New TNavBar
+               n.host=host     
+               n.tabber=CreateTabber(0,0,ClientWidth(parent),ClientHeight(parent),parent)
+               SetGadgetLayout(n.tabber,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED)
+'              n.AddView root
+               n.navmenu=CreateNavMenu()
+               Return n                
+       End Function
+
+End Type
+
+Type TOutputPanel Extends TToolPanel   'used build and run
+
+       Field   host:TCodePlay
+       Field   output:TGadget
+       
+       Field   process:TProcess
+       Field   pipe:TStream
+
+       Field   wpipe:TTextStream
+
+       Field   user$,cmdline$,err$,post$
+       Field   errbuffer:TByteBuffer
+       Field   outputmenu:TGadget
+       Field   posttool:TTool
+       
+       Method ClearDumpRequests()
+               For Local o:TObj = EachIn MapValues(host.debugtree.objmap)
+                       o.HasSynced(o.sync)
+               Next
+       EndMethod
+       
+       Method SendDumpRequests()
+               For Local o:TObj = EachIn MapValues(host.debugtree.objmap)
+                       If o.syncnext Then
+                               If o.addr <> "00000000" Then WritePipe "d"+o.addr
+                               o.HasSynced( host.debugtree.sync )
+                       EndIf
+               Next
+       EndMethod
+       
+       Method Clear()
+               If Not output Open()
+               SetGadgetText output,""
+       End Method
+       
+       Method WriteAscii(mess$)
+               If Not output Open()
+               AddTextAreaText output,mess.Replace("~0","")
+       End Method
+
+       Method Write(mess$)
+               If Not output Open()
+               AddTextAreaText output,mess.Replace("~0","")
+       End Method
+
+       Method Execute(cmd$,mess$="",exe$="",home=True,owner:TTool=Null)
+               If Not output Open()
+               If Not mess$ mess$=cmd$
+               err$=""
+               post$=exe
+               posttool=owner
+               host.SelectPanel Self
+               host.debugtree.Reset
+               
+               If process And ProcessStatus(process)
+                       Delay 500
+                       If ProcessStatus(process)
+                               Notify LocalizeString("{{output_notification_stillbusy}}").Replace("%1",cmdline)
+                               Return
+                       EndIf
+               EndIf
+               cmd=cmd.Trim()
+               process=CreateProcess(cmd$,HIDECONSOLE)
+               If Not process Then Notify LocalizeString("{{output_notification_processfailure}}").Replace("%1",cmd);Return
+               If Not process.status() Then Notify LocalizeString("{{output_notification_failedstart}}").Replace("%1",cmd);process=Null;Return         
+               pipe=Process.pipe
+               wpipe=TTextStream.Create(pipe,TTextStream.UTF8)
+
+               cmdline=cmd
+               If home Clear
+               Write( mess+"~n" )
+               errbuffer = New TByteBuffer
+               host.RefreshToolbar     
+
+       End Method
+
+       Method WritePipe(l$)    
+               Try
+                       If pipe pipe.WriteLine(l)
+               Catch ex:TStreamWriteException
+                       Write LocalizeString("{{output_msg_debugfailure}}~n").Replace("%1",l)
+                       Stop
+               EndTry  
+       End Method
+
+       Method Go()
+               WritePipe "r"
+               host.debugtree.cancontinue = False
+               host.SelectPanel Self
+               host.RefreshToolbar()
+       End Method
+       
+       Method StepOver()
+               ClearDumpRequests()
+               WritePipe "s"
+       End Method
+       
+       Method StepIn()
+               ClearDumpRequests()
+               WritePipe "e"
+       End Method
+
+       Method StepOut()
+               ClearDumpRequests()
+               WritePipe "l"
+       End Method
+       
+       Method Stop()
+               If Not process Return           
+               process.Terminate()
+               FlushPipes process.pipe,process.err             
+               process.Close()
+               process=Null
+               Write LocalizeString("~n{{output_msg_processterminated}}~n")
+               host.DebugExit()
+               Close()
+       End Method
+       
+       Method Wait()
+               While process And process.status()
+                       PollSystem
+               Wend
+       End Method
+       
+       Method Invoke(command,argument:Object=Null)
+               Select command
+                       Case TOOLSHOW
+                               host.SetTitle()
+                               If output ActivateGadget output 
+                       Case TOOLCLOSE
+                               host.RemovePanel Self
+                               output=Null
+                       Case TOOLCUT
+                               GadgetCut output
+                       Case TOOLCOPY
+                               GadgetCopy output
+                       Case TOOLPASTE
+                               GadgetPaste output
+                       Case TOOLSELECTALL
+                               If output SelectTextAreaText output
+                       Case TOOLREFRESH
+                               host.options.outputstyle.apply output
+               End Select
+       End Method
+       
+       Method Close()
+               host.SelectPanel host.activepanel
+       End Method
+       
+       Method Escape()
+               Stop
+               Close
+       End Method
+       
+       Function outputfilter(event:TEvent,context:Object)
+               Local out:TOutputPanel=TOutputPanel(context)
+               If Not out Return
+               Select event.id
+                       Case EVENT_KEYDOWN
+                               If event.data=27
+                                       out.Escape()
+                                       Return 0
+                               EndIf
+                       Case EVENT_KEYCHAR
+'                              Print "output_keychar "+event.data
+                               out.writechar(event.data)
+               End Select
+               Return 1
+       End Function
+       
+       Method OnEvent()
+               If EventSource()=output
+                       If EventID()=EVENT_GADGETMENU
+                               PopupWindowMenu host.window,outputmenu
+                       EndIf
+               EndIf
+' Case EVENT_TIMERTICK
+               If Not process Return           
+               
+               ReadPipes process.pipe,process.err
+               
+               If Not process.status()
+                       process.terminate
+                       FlushPipes process.pipe,process.err
+                       process.close()
+                       process = Null
+                       Write LocalizeString("~n{{output_msg_processcomplete}}~n")
+                       host.DebugExit
+                       host.SelectPanel Self
+
+                       If err
+                               host.ParseError err
+                       Else
+                               If post$
+                                       Local menuaction=Int(post)
+                                       If menuaction
+                                               host.OnMenu menuaction,posttool
+'                                      Else                            
+'                                              Execute post$,"","",False,0
+                                       EndIf
+                               Else
+                                       If host.options.hideoutput Close()
+                               EndIf
+                       EndIf
+               EndIf   
+               
+       End Method
+               
+       Method FlushPipes(pipe:TPipeStream,errpipe:TPipeStream)
+               ReadPipes(pipe,errpipe)
+               Local bytes:Byte[] = errbuffer.flushbytes()
+               If bytes
+                       Local line$=String.FromBytes(bytes,Len bytes)
+                       line=line.Replace(Chr(13),"")
+                       If line<>">" Write line
+               EndIf
+       End Method
+               
+       Method ReadPipes(pipe:TPipeStream,errpipe:TPipeStream)
+               Local   status
+               Local   bytes:Byte[],line$
+
+               bytes=pipe.ReadPipe()
+               If bytes
+                       line$=String.FromBytes(bytes,Len bytes)
+                       line=line.Replace(Chr(13),"")
+                       Write line
+               EndIf
+               
+               If errpipe.ReadAvail() Then
+                       errbuffer.WriteFromPipe(errpipe)
+               Else
+                       SendDumpRequests()
+               EndIf
+               
+'              If bytes Write String.FromBytes(bytes,bytes.length)
+               While errbuffer.LineAvail()
+                       line$=errbuffer.ReadLine()
+                       line=host.debugtree.ProcessError(line)
+                       If line
+                               Write line+"~n"
+                               err:+line+"~n"
+                       EndIf
+               Wend
+               
+       End Method
+       
+       Method WriteChar(char)
+               Local   pipe:TPipeStream
+                               
+               If Not process Return           
+               pipe=process.pipe
+               If char=3                       'CTRL-C
+                       Stop()
+               EndIf
+               If char=13                      'ENTER
+'                      Write Chr(10)
+                       pipe.WriteLine user$
+                       user=""
+               EndIf
+               If char=8 And user.length                       'DELETE
+'                      Local pos=TextAreaLen(output)
+'                      If pos SetTextAreaText output,"",pos-1,1,TEXTAREA_CHARS
+                       user=user[..user.length-1]
+               EndIf
+               If char>31
+'                      Write Chr(char)
+                       user:+Chr(char)
+               EndIf
+       End Method
+               
+       Method Open()
+               If output Then
+                       codeplay.SelectPanel Self
+                       Return
+               EndIf
+               codeplay.addpanel(Self)         
+               output=CreateTextArea(0,0,ClientWidth(panel),ClientHeight(panel),panel,TEXTAREA_WORDWRAP)
+               DelocalizeGadget output
+               SetGadgetLayout output,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+               SetGadgetFilter output,outputfilter,Self
+               SetGadgetText output," "        'simon was here         
+               host.options.outputstyle.apply output
+       End Method
+
+       Function CreateOutputMenu:TGadget()
+               Local   edit:TGadget = CreateMenu("{{popup_output}}",0,Null)
+               CreateMenu "{{popup_output_cut}}",MENUCUT,edit
+               CreateMenu "{{popup_output_copy}}",MENUCOPY,edit
+               CreateMenu "{{popup_output_paste}}",MENUPASTE,edit
+               CreateMenu "",0,edit
+               CreateMenu "{{popup_output_stop}}",MENUSTOP,edit
+               Return edit
+       End Function
+
+       Function Create:TOutputPanel(host:TCodePlay)
+               Local   o:TOutputPanel = New TOutputPanel
+               o.host=host             
+               o.name="{{tab_output}}"
+               o.outputmenu=CreateOutputMenu()
+'              o.Open
+               Return o
+       End Function
+
+End Type
+
+Type TCodeNode Extends TNode
+       Field   owner:TOpenCode
+       Field   pos,count
+       'Field  groups:TMap=New TMap
+
+       Method Invoke(command,argument:Object=Null)
+               Select command
+                       Case TOOLACTIVATE
+                               owner.ShowPos(pos)
+               End Select
+       End Method
+
+       Method Sync(snap:TNode) 
+               If snap.name<>name SetName(snap.name)
+               Local   n:TCodeNode = TCodeNode(snap)
+               If n pos=n.pos;count=n.count
+               Super.Sync(snap)
+       End Method
+       
+       Method SetName(n$)
+               Local   p = n.find("'")
+               If p<>-1 n=n[..p]
+               name=n.Trim()
+'              If owner.host.options.sortcode
+               sortname=n
+       End Method
+       
+       Method Free()
+               owner = Null
+               Super.Free()
+       End Method
+       
+       Method AddCodeNode:TCodeNode(n$,p0,p1)
+               
+               Local t$
+               Local i:Int = n.find(" ")       'if space then group
+               
+               If i>0
+                       t=n[..i]
+                       n=n[i+1..]
+Rem
+                       p=TNode(groups.ValueForKey(t))
+                       If Not p
+                               p=AddNode(t+"s")
+                               p.Open
+                               groups.insert t,p
+                       EndIf
+EndRem
+               EndIf
+               
+               Local c:TCodeNode = New TCodeNode
+               c.owner=owner
+               c.setname n$
+               c.pos=p0
+               c.count=p1-p0
+               Append(c)
+               
+               Return c
+               
+       End Method
+End Type
+
+Type TDiff
+       Field   pos,count,del$,add$,pos0,count0,pos1,textchange = True
+End Type
+
+Type TOpenCode Extends TToolPanel
+       
+       Global msgHighlightingStatus$ = "Highlighting"
+       
+       Field   host:TCodePlay
+       Field   textarea:TGadget
+       Field   dirty=True
+       Field   filesrc$,cleansrc$,cleansrcl$
+       Field   Current:TDiff
+       Field   undolist:TList=New TList
+       Field   redolist:TList=New TList
+       Field   helpcmd$,helpstring$
+       Field   seek$
+       Field   cursorpos,cursorlen,cursorline
+       Field   oldpos,oldlen
+       Field   isbmx,isc,iscpp,ishtml
+       Field   deferpos = -1
+       Field tidyqueue1 = -1, tidyqueue2 = -1
+       Field   editmenu:TGadget
+       Field   codenode:TCodeNode
+       Field   dirtynode,uc
+       
+       Function RefreshHighlightingMsg()
+               msgHighlightingStatus = LocalizeString("{{msg_highlightingcode}}")
+       EndFunction
+       
+       Function IsNotAlpha(c)
+               If c<48 Return True
+               If c>=58 And c<65 Return True
+               If c>=91 And c<95 Return True
+               If c>=96 And c<97 Return True
+               If c>=123 Return True
+       End Function
+       
+       Function WordAtPos$(a$,p)
+               Local   c,q,r,n
+       ' string literal
+               q=a.findlast(EOL$,a.length-p)
+               If q=-1 q=0
+               For q=q To p-1
+                       If a[q]=34 Then
+                               n=Not n
+                               r=q
+                       EndIf
+               Next
+               If n    
+                       q=a.Find("~q",r+1)+1
+                       If q=0 q=a.length
+                       Return a[r..q]
+               EndIf
+       ' alphanumeric
+               p=Min(p,a.length-1)     'simon was here - crash when checking at last char
+               For p=p Until 0 Step -1 'simon was here unto->to
+                       If IsNotAlpha(a$[p]) Continue
+                       Exit
+               Next
+               For q=p-1 To 0 Step -1
+                       If IsNotAlpha(a$[q]) Exit
+               Next
+               For r=p To a.length-1
+                       If IsNotAlpha(a$[r]) Exit
+               Next
+               Return a[q+1..r]
+       End Function
+       
+       Function FirstDiff(s0$,s1$)
+               Local   n = Min(s0.length,s1.length)
+               For Local i:Int = 0 Until n
+                       If s0[i]<>s1[i] Return i
+               Next
+               Return n                
+       End Function
+       
+       Function LastDiff(s0$,s1$)
+               Local n = Min(s0.length,s1.length)
+               Local i = s0.length-1
+               Local j = s1.length-1
+               While n>0
+                       If s0[i]<>s1[j] Exit
+                       i:-1;j:-1;n:-1
+               Wend
+               Return i+1
+       End Function
+       
+       Method parsebmx(n:TCodeNode)
+               Local   src$,line,col
+               Local   p,p1,r,t,m,f,l,e
+
+               src=cleansrcl
+               p1=src.length
+               p=-1;r=-1;t=-1;m=-1;f=-1;l=-1
+               While p<p1                      'update rem,type,method,function,label pointers
+                       While r<=p
+                               r=FindToken("rem",src,r+1)
+                       Wend
+                       While t<=p
+                               t=FindToken("type",src,t+1)
+                       Wend
+                       While m<=p
+                               m=FindToken("method",src,m+1)
+                       Wend
+                       While f<=p
+                               f=FindToken("function",src,f+1)
+                       Wend
+                       While l<=p
+                               l=FindLabel(src,l+1)
+                       Wend
+                       If r<t And r<m And r<f And r<l
+                               p=FindEndToken("rem",src,r+1,True)
+                               Continue
+                       EndIf
+                       p=Min(t,Min(m,Min(f,l)))
+                       If p=src.length Exit            
+                       While (n And n.parent And p>n.pos+n.count)
+                               If Not TCodeNode(n.parent)
+                                       If n.parent.parent
+                                               n = TCodeNode(n.parent.parent)
+                                       Else
+                                               n = Null
+                                       EndIf
+                               Else
+                                       n=TCodeNode(n.parent)
+                               EndIf
+                       Wend
+                       If t<m And t<f And t<l
+                               e=src.find(EOL,t)
+                               n=n.AddCodeNode(cleansrc[t..e],t,FindEndToken("type",src,t,True))
+                               p=t+1
+                               Continue
+                       EndIf
+                       If m<f And m<l
+                               e=src.find(EOL,m)
+                               n.AddCodeNode(cleansrc[m..e],m,e)
+                               p=m+1
+                               Continue
+                       EndIf
+                       If f<l
+                               e=src.find(EOL,f)
+                               n.AddCodeNode(cleansrc[f..e],f,e)
+                               p=f+1
+                               Continue                
+                       Else
+                               e=src.find(EOL,l)
+                               n.AddCodeNode(cleansrc[l..e],l,e)
+                               p=l+1
+                               Continue                                
+                       EndIf
+               Wend
+       End Method
+       
+       Method GetNode:TNode()
+               Local   root:TCodeNode = New TCodeNode
+               root.name = StripDir(path)
+               root.owner = Self
+               root.count = cleansrc.length
+               If isbmx parsebmx(root) ' stopped code view parse on non bmx files
+               If codenode
+                       If host.options.sortcode root.sortkids
+                       codenode.Sync(root)     
+                       root.Free()
+               Else
+                       codenode=root
+               EndIf
+               Return codenode
+       End Method
+       
+       Method HighlightLine(line,column = 0)
+               Local i:Int, tmpCharLineStart% = TextAreaChar(textarea,line)
+               Local tmpLine$ = TextAreaText( textarea, line, 1, TEXTAREA_LINES ).Replace("~r","").Replace("~n","")
+               For i = column Until tmpLine.length
+                       If IsNotAlpha(tmpLine[i]) Then tmpCharLineStart:+1 Else Exit
+               Next
+               SelectTextAreaText textarea,line-1,0,TEXTAREA_LINES
+               SelectTextAreaText textarea,line+1,0,TEXTAREA_LINES
+               If i = tmpLine.length Or ..
+               ( TextAreaCharX( textarea, tmpCharLineStart + tmpLine.length-i ) - TextAreaCharX( textarea, tmpCharLineStart ) >= ClientWidth(textarea) ) Then
+                       SelectTextAreaText textarea,line,1,TEXTAREA_LINES
+               Else
+                       SelectTextAreaText textarea,tmpCharLineStart,tmpLine.length-i,TEXTAREA_CHARS
+               EndIf
+       EndMethod
+       
+       Method ShowPos(pos)
+               host.SelectPanel( Self )
+               HighlightLine( TextAreaLine(textarea,pos) )
+               UpdateCursor()
+               ActivateGadget( textarea )
+       End Method
+
+       Method Debug(line,column)
+               HighlightLine( line-1 )
+               UpdateCursor()
+       End Method
+
+       Method Edit()
+               SelectTextAreaText( textarea,cursorpos,0,TEXTAREA_CHARS )
+               ActivateGadget( textarea )
+               UpdateStatus()
+       End Method
+       
+       Method UpdateStatus()
+               Local   c = cursorpos+cursorlen
+               If cursorline Then c:-TextAreaChar(textarea,cursorline-1)
+               host.SetStatus helpstring+"~t~t"+LocalizeString("{{status_line_char}}").Replace("%1",cursorline).Replace("%2",(c+1))
+       End Method
+       
+       Method UpdateCursor()
+               oldpos=cursorpos
+               oldlen=cursorlen
+               cursorpos=TextAreaCursor(textarea,TEXTAREA_CHARS)
+               cursorlen=TextAreaSelLen(textarea,TEXTAREA_CHARS)
+               If cursorpos<>oldpos Or cursorlen<>oldlen
+                       Local   l = TextAreaLine(textarea,cursorpos)+1
+                       If l<>cursorline And dirtynode
+                               GetNode().Refresh
+                               dirtynode=False
+                               If (deferpos>=0) UpdateCode     'SetCode cleansrc
+                       EndIf
+                       cursorline=l
+                       UpdateStatus()
+                       BracketMatching(cleansrcl)
+                       If (tidyqueue1 >= 0 Or tidyqueue2 >= 0) Then UpdateCode()
+                       PollSystem
+               EndIf
+       End Method
+
+' tdiff - pos del$ add$
+
+       Method CalcDiff:TDiff(src$)
+               Local   d:TDiff
+               If src.length<>cleansrc.length
+                       d=New TDiff
+                       d.pos0=cursorpos
+                       d.count0=cursorlen
+                       d.pos=oldpos
+                       d.count=oldlen
+                       If cursorlen And oldlen                                                 'block modified
+                               d.del=cleansrc[oldpos..oldpos+oldlen]
+                               d.add=src[oldpos..cursorpos+cursorlen]
+                               d.pos1=oldpos
+                       Else
+                               If cursorpos<=oldpos And cursorlen<=oldlen      'backspace
+                                       d.del=cleansrc[cursorpos..cursorpos+cleansrc.length-src.length]
+                                       d.pos1=cursorpos
+                               Else                                                                            'insert
+                                       d.del=cleansrc[oldpos..oldpos+oldlen]
+                                       d.add=src[oldpos..cursorpos+cursorlen]
+                                       d.pos1=oldpos
+                               EndIf
+                       EndIf   
+               Else            
+                       If cursorpos>oldpos                                                                     'overwrite
+                               d=New TDiff
+                               d.pos0=cursorpos
+                               d.count0=cursorlen
+                               d.pos=oldpos
+                               d.count=oldlen
+                               d.del=cleansrc[oldpos..cursorpos]
+                               d.add=src[oldpos..cursorpos]
+                               d.pos1=oldpos
+                               If d.del = d.add Then d.textchange=False
+                       EndIf
+               EndIf
+               Return d        
+       End Method
+
+       Method UpdateCode(makeundo=True)
+               Local   cpos
+               Local src$ = TextAreaText(textarea)
+               Local d:TDiff = CalcDiff(src)
+               If d
+                       If makeundo And d.textchange
+                               undolist.AddLast d
+                               redolist.Clear
+                       EndIf
+                       SetCode src,d
+                       If d.textchange Then dirtynode=True
+               EndIf
+               If (deferpos >= 0) Or (tidyqueue1 >= 0) Or (tidyqueue2 >= 0) Then SetCode src
+       End Method
+       
+       Method Undo()
+               Local   d:TDiff
+               If undolist.IsEmpty() Return
+               d=TDiff(undolist.RemoveLast())
+               redolist.AddLast d
+               SetTextAreaText textarea,d.del,d.pos1,d.add.length
+               SelectTextAreaText(textarea,d.pos,d.count)
+               SetCode TextAreaText(textarea),d
+               UpdateCursor
+       End Method
+
+       Method Redo()
+               Local   d:TDiff
+               If redolist.IsEmpty() Return
+               d=TDiff(redolist.RemoveLast())
+               undolist.AddLast d
+               SetTextAreaText textarea,d.add,d.pos,d.del.length
+               SelectTextAreaText(textarea,d.pos0,d.count0)
+               UpdateCursor
+               SetCode TextAreaText(textarea),d
+       End Method
+
+       Method RefreshStyle()
+               Local   rgb:TColor
+               Local   src$
+               Local charwidth                         
+               charwidth=host.options.editfont.CharWidth(32)
+               SetTextAreaTabs textarea,host.options.tabsize*charwidth         
+               SetMargins textarea,4           
+               SetTextAreaFont textarea,host.options.editfont
+               rgb=host.options.editcolor
+               SetTextAreaColor textarea,rgb.red,rgb.green,rgb.blue,True
+               rgb=host.options.styles[0].color
+               SetTextAreaColor textarea,rgb.red,rgb.green,rgb.blue,False
+               src=cleansrc
+               cleansrc=""
+               cleansrcl=""
+               cursorpos=0
+               SetCode(src)
+       End Method
+
+       Function IsntAlphaNumeric(c)            'lowercase test only
+               If c<48 Return True
+               If c>=58 And c<95 Return True
+               If c=96 Return True
+               If c>=123 Return True
+       End Function
+       
+       Function IsntAlphaNumericOrQuote(c)             'lowercase test only
+               If c=34 Return False
+               If c<48 Return True
+               If c>=58 And c<95 Return True
+               If c=96 Return True
+               If c>=123 Return True
+       End Function
+
+       Function IsCode(src$,p)
+               Local n
+               Local l = src.FindLast(EOL$,src.length-p)
+               If l=-1 l=0
+               Local q = src.Find("'",l)
+               If q<>-1 And q<p Return
+               q=l
+               While q<p
+                       q=src.Find(QUOTES$,q)+1
+                       If q=0 Exit
+                       If q<=p n:+1
+               Wend
+               Return Not(n&1)
+       End Function
+
+       Function FindLabel(src$,pos)
+               Local   p,q,c
+               While pos>=0
+                       p=src.Find("#",pos)
+                       If p=-1 Exit
+                       q=p
+                       While q>0
+                               q:-1
+                               c=src[q]
+                               If c=13 Return p
+                               If c=10 Return p
+                               If c=32 Or c=9 Continue
+                               Exit
+                       Wend
+                       If q<0 Return p
+                       pos=p+1
+               Wend
+               Return src.length       
+       End Function
+       
+       Function FindToken(token$,src$,pos)     'lowercase src only!
+               Local p,c
+               Local n=token.length
+               While pos>=0
+                       p=src.Find(token,pos)
+                       If p=-1 Exit
+                       c=10 If p>0 c=src[p-1]
+                       If isntalphanumeric(c)
+                               If p+n<src.length c=src[p+n]
+                               If isntalphanumeric(c)
+                                       If iscode(src,p)
+                                               If p<4 Or src[p-4..p]<>"end " Return p
+                                       EndIf
+                               EndIf
+                       EndIf
+                       pos=p+1
+               Wend
+               Return src.length
+       End Function
+
+       Function FindEndToken(token$,src$,pos,returnlast=False) 'if true returns first character after endtoken
+               Local   p,q,e$,n
+               
+               p=pos
+               e$="end"+token
+               n=e.length
+               While p<src.length
+                       p=src.Find(e$,p)
+                       If p=-1 Exit
+                       If p+n=src.length Or isntalphanumeric(src[p+n])
+                               If iscode(src,p)
+                                       If p=0 Or isntalphanumeric(src[p-1]) Exit
+                               EndIf
+                       EndIf
+                       p=p+n
+               Wend
+               If p=-1 p=src.length Else If returnlast p:+n
+               q=pos
+               e$="end "+token
+               n=e.length
+               While q<src.length
+                       q=src.Find(e$,q)
+                       If q=-1 Exit
+                       If q+n=src.length Or isntalphanumeric(src[q+n])
+                               If iscode(src,q)
+                                       If q=0 Or isntalphanumeric(src[q-1]) Exit
+                               EndIf
+                       EndIf
+                       q=q+n
+               Wend
+               If q=-1 q=src.length Else If returnlast q:+n
+               Return Min(p,q)
+       End Function
+
+       Function IsFirstCharOnLine(src$,pos)
+               Local   c
+               For Local i:Int = 1 To pos
+                       c=src[pos-i]
+                       If c=10 Or c=13 Return True
+                       If c>32 Return False
+               Next
+               Return True
+       End Function
+
+' rem and endrem must be first nonwhitespace on line - following funcs are for lowercase src only
+
+       Function FindRem(src$,pos)
+               While pos<src.length
+                       pos=FindToken("rem",src,pos)
+                       If pos=src.length Exit
+                       If IsFirstCharOnLine(src,pos) Return pos
+                       pos:+1
+               Wend
+               Return pos
+       End Function
+
+       Function FindEndRem(src$,pos,returnlast=False)
+               Local   i,c             
+               While pos<src.length
+                       pos=FindEndToken("rem",src,pos)
+                       If pos=src.length Exit
+                       If IsFirstCharOnLine(src,pos)
+                               If returnlast
+                                       If src[pos+5]=Asc("e") Or src[pos+5]=Asc("E") pos:+1
+                                       pos:+6
+                               EndIf
+                               Return pos
+                       EndIf
+                       pos:+1
+               Wend
+               Return src.length
+       End Function
+
+       Function FindPrevRem(src$,pos)  'lowercase src only!
+               Local   p,c
+               While pos>0
+                       If pos>src.length Exit  'fixed endrem on lastline overrun
+                       p=src.FindLast("rem",src.length-pos)
+                       If p=-1 Exit                                            
+                       If isntalphanumeric(src[p+3]) And IsFirstCharOnLine(src,p) Return p                     
+                       pos=p-1
+               Wend
+               Return -1
+       End Function
+       
+       Method IsRemmed(pos,src$)
+               Local p = FindPrevRem(src$,Min(pos+3,src.length))
+               If p<0 Return
+               p=FindEndRem(src$,p)
+               If p<0 Or pos<p Return True
+       EndMethod
+       
+       Method WasRemmed(pos,src$)
+               Local s$ = cleansrcl
+               Local p = (src.length-s.length)
+               If p<0 pos:-p
+               p=FindPrevRem(s$,Min(pos+3,s.length))
+               If p<0 Return
+               p=FindEndRem(s$,p)
+               If pos<p Return True
+       End Method
+
+       Method CheckDirty(src$)
+               SetDirty (Not (src=filesrc And undolist.IsEmpty()))
+       End Method
+       
+       Method HasTidyQueue()
+               Return ((deferpos >= 0) Or (tidyqueue1 >= 0) Or (tidyqueue2 >= 0))
+       EndMethod
+       
+       Method ClearTidyQueue(start,endpos)
+               If start<=deferpos And deferpos < endpos Then deferpos = -1
+               If start<=tidyqueue1 And tidyqueue1 < endpos Then tidyqueue1 = -1
+               If start<=tidyqueue2 And tidyqueue2 < endpos Then tidyqueue2 = -1
+       EndMethod
+       
+       Method SetCode(src$,diff:TDiff=Null)
+               Local   same,i,p,startp,p1,q,r,a,t$,h$,lsrc$,r0,r1,cpos,autocap
+               Local   style:TTextStyle[5],s:TTextStyle
+' update dirty flag    
+               CheckDirty src
+               same = Not ((diff) Or (src<>cleansrc))
+               If same And Not (diff Or HasTidyQueue()) Then Return    
+               If Not isbmx Or Not host.quickhelp Or Not host.options.syntaxhighlight
+                       If Not same Then
+                               cleansrc=src
+                               cleansrcl=src.ToLower()
+                       EndIf
+                       Return
+               EndIf
+' doit
+               autocap=host.options.autocapitalize
+               If same Then lsrc = cleansrcl Else lsrc=src.ToLower()
+               cpos=TextAreaCursor(textarea,TEXTAREA_CHARS)
+               LockTextArea textarea
+               style=host.options.styles
+' calculate highlight region
+               
+               If diff
+                       p=diff.pos
+                       p1=p+diff.add.length
+                       If Not diff.add.length Then
+                               p:-diff.del.length
+                       EndIf
+               ElseIf HasTidyQueue()
+                       p=src.length
+                       If (deferpos>=0) Then
+                               p = Min(p,deferpos)
+                               p1 = Max(p1,deferpos+1)
+                       EndIf
+                       If (tidyqueue1>=0) Then
+                               p = Min(p,tidyqueue1)
+                               p1 = Max(p1, tidyqueue1+1)
+                       EndIf
+                       If (tidyqueue2>=0) Then
+                               p = Min(p,tidyqueue2)
+                               p1 = Max(p1, tidyqueue2+1)
+                       EndIf
+               Else
+                       p=firstdiff(src,cleansrc)
+                       p1=lastdiff(src,cleansrc)
+               EndIf
+               q=src.length-cleansrc.length
+               If p1-p<q p1=p+q
+               If p1<p p1=p
+               
+' round region to line breaks
+               'Print "p="+p+" p1="+p1
+               If p>src.length p=src.length
+               p=src.findlast(EOL,src.length-(p-1))+1
+               p1=src.find(EOL,p1)+1
+               If p1=0 p1=src.length
+' if endrem between p0,p1 and next rem after p1 move p1 forwards
+               r1=FindEndRem(lsrc,p)
+               If r1<p1 And wasremmed(r1+6,lsrc)
+                       r0=FindRem(lsrc,r1+6)
+                       If r0>p1 p1=r0
+               EndIf
+' if rem between p0,p1 and matching endrem after p1 move p1 forewards
+               r0=FindPrevRem(lsrc,p1)
+               If r0>=p And r0+3<>cpos 'defer fix
+                       r1=FindEndRem(lsrc,r0,True)
+                       If r1>p1 p1=r1
+               EndIf
+' if rem before p0 and matching endrem after p0 highlight to endrem and move p0 forwards
+               r0=FindPrevRem(lsrc,p)
+               If r0<>-1 And r0<p
+                       r1=FindEndRem(lsrc,r0,True)
+                       If r1>p
+                               s=style[COMMENT]
+                               If r1>p s.Format(textarea,p,r1-p)
+                               If autocap And r1<src.length
+                                       If lsrc[r1-6..r1]="endrem" And src[r1-6..r1]<>"EndRem" SetTextAreaText textarea,"EndRem",r1-6,6
+                                       If lsrc[r1-7..r1]="end rem" And src[r1-7..r1]<>"End Rem" SetTextAreaText textarea,"End Rem",r1-7,7
+                               EndIf
+                               ClearTidyQueue(p,r1)
+                               p=r1
+                       EndIf
+               EndIf   
+' if was remmed and now isn't move p1 down to nearest rem or endrem
+               If WasRemmed(p,lsrc)
+                       r0=FindRem(lsrc,p)
+                       r1=FindEndRem(lsrc,r0,True)
+                       p1=Max(p1,Min(r0,r1))   
+               EndIf
+' highlight code
+               ClearTidyQueue(p,p1)
+               
+               s=style[NORMAL]
+               If p1>p s.format(textarea,p,p1-p)
+               startp = p
+               
+               While p<p1
+                       host.UpdateProgress(msgHighlightingStatus,(p*100)/p1)
+                       a=src[p]
+' quoted strings
+                       If a=34
+                               q=p1
+                               r=src.Find(Chr(34),p+1)
+                               If r>-1 And r<q q=r+1
+                               r=src.Find(EOL,p+1)
+                               If r>-1 And r<q q=r
+                               s=style[QUOTED]
+                               s.format(textarea,p,q-p)
+                               p=q
+                               Continue
+                       EndIf
+' single line comments
+                       If a=39
+                               q=p1
+                               r=src.Find(EOL,p+1)
+                               If r>-1 And r<q q=r
+                               s=style[COMMENT]
+                               s.format(textarea,p,q-p)
+                               p=q
+                               Continue                                
+                       EndIf
+' tokens
+                       If (a>=65 And a<91) Or (a>=97 And a<123) Or (a=95)
+                               q=p+1
+                               While q<p1
+                                       a=src[q]
+                                       If a<48 Exit    'changed to include dot (chr 47)
+                                       If a>=58 And a<65 Exit
+                                       If a>=91 And a<95 Exit
+                                       If a=96 Exit
+                                       If a>122 Exit
+                                       q:+1
+                               Wend
+                               t$=src[p..q]
+                               h$=host.quickhelp.token(t$)
+                               If h$
+                                       If h$<>t$ And autocap
+                                               If cpos<p Or cpos>q
+                                                       SetTextAreaText textarea,h,p,h.length
+                                               Else
+                                                       deferpos=q
+                                               EndIf
+                                       EndIf
+                                       s=style[KEYWORD]
+                                       If h$="Rem" And IsFirstCharOnLine(lsrc,p)       ' Not (p>4 And lsrc[p-4..p]="end ")
+                                               If q<>cpos
+                                                       q=FindEndRem(lsrc,p,True)
+                                                       s=style[COMMENT]
+                                               Else
+                                                       deferpos=q
+                                               EndIf                                           
+                                       EndIf
+                                       s.format(textarea,p,q-p)
+                               EndIf
+                               p=q
+                               Continue
+                       EndIf
+' numbers
+                       If (p=0 Or IsntAlphaNumeric(lsrc[p-1])) And ((a>=$30 And a<$3A) Or (a=$24) Or (a=$25) Or (a=$2E))       '0-9, $, %, .
+                               q=p+1
+                               Local hexed:Int = (a=$24), binaried:Int = (a=$25), dots:Int = (a=$2E)
+                               Local valid:Int = Not(hexed Or binaried Or dots)
+                               
+                               While q<(p1)
+                                       a=lsrc[q]
+                                       q:+1
+                                       If (a>=$30 And a<$3A) Then
+                                               valid = True
+                                               Continue        '0-9
+                                       EndIf
+                                       If hexed
+                                               If (a>=$61 And a<$67) Then      'a-f (only test lower as 'a' var is from lsrc)
+                                                       valid = True
+                                                       Continue
+                                               EndIf
+                                       EndIf
+                                       If (a=$2E) Then
+                                               'Hex or Binary literals don't support decimal points
+                                               If Not (hexed Or binaried) Then
+                                                       dots:+1
+                                                       'Fix for slicing '..' syntax
+                                                       If src[q-2] = $2E Then
+                                                               dots:-2
+                                                               q:-2
+                                                               Exit
+                                                       EndIf
+                                                       'End Fix
+                                                       Continue
+                                               EndIf
+                                       EndIf
+                                       If Not IsntAlphaNumeric(a) Then valid = False
+                                       q:-1
+                                       Exit
+                               Wend
+                               If valid And dots < 2 Then style[NUMBER].format(textarea,p,(q-p))
+                               'Fix for slicing '..' syntax
+                               If q<src.length And (src[q]=Asc(".")) Then q:+1
+                               If q<src.length And (src[q]=Asc(".")) Then q:+1
+                               'End Fix
+                               p=q
+                               Continue
+                       EndIf
+                       p:+1
+               Wend
+               BracketMatching(lsrc,startp,p1,True)
+               UnlockTextArea textarea
+               If Not same
+                       cleansrc=src
+                       cleansrcl=lsrc
+               EndIf
+'              CheckDirty src  simon was here
+       End Method
+       
+       Field currentbrackets:Int[]
+       
+       Method BracketMatching(lsrc$,cln1=-1,cln2=-1,alwaysfind:Int = False)
+               
+               Local check:Int, depth:Int, style:TTextStyle[] = host.options.styles
+               Local otherchar:Int = 0, absotherchar:Int = 0, othercharpos:Int = 0, limit:Int
+               Local currentchar:Int = 0, currentcharpos:Int = Max(cursorpos-1,0)
+               
+               If cursorlen Then Return
+               
+               If currentbrackets Then
+                       If Not(cln2 > currentbrackets[0] And cln1 <= currentbrackets[0]) Then
+                               If currentbrackets[0]>-1 Then tidyqueue1 = currentbrackets[0]
+                       EndIf
+                       If Not(cln2 > currentbrackets[1] And cln1 <= currentbrackets[1]) Then
+                               If currentbrackets[1]>-1 Then tidyqueue2 = currentbrackets[1]
+                       EndIf
+                       currentbrackets = Null
+                       If Not alwaysfind Then Return
+               EndIf
+               
+               If host.options.bracketmatching And isbmx And Not IsRemmed(currentcharpos,lsrc) Then
+                       
+                       limit = Min(lsrc.length,currentcharpos+2)
+                       
+                       While currentcharpos >= 0 And currentcharpos < limit
+                               If IsCode(lsrc,currentcharpos) Then
+                                       Select lsrc[currentcharpos]
+                                               Case Asc("(");otherchar = Asc(")");Exit
+                                               Case Asc("{");otherchar = Asc("}");Exit
+                                               Case Asc("[");otherchar = Asc("]");Exit
+                                               ' Negate char code to search backwards
+                                               Case Asc(")");otherchar = -Asc("(");Exit
+                                               Case Asc("}");otherchar = -Asc("{");Exit
+                                               Case Asc("]");otherchar = -Asc("[");Exit
+                                       EndSelect
+                               EndIf
+                               currentcharpos:+1
+                       Wend
+                       
+                       If otherchar Then
+                               
+                               absotherchar = (Abs otherchar)
+                               currentchar = lsrc[currentcharpos]
+                               
+                               LockTextArea textarea
+                               style[MATCHING].format(textarea, currentcharpos, 1)
+                               currentbrackets = [currentcharpos,-1]
+                               
+                               othercharpos =  currentcharpos+(otherchar/absotherchar)
+                               
+                               While othercharpos < lsrc.length And othercharpos >= 0
+                                       
+                                       If IsCode(lsrc,othercharpos) Then
+                                               Select lsrc[othercharpos]
+                                                       Case Asc(" "), Asc("~t")
+                                                               'Do nothing
+                                                       Case Asc("'")
+                                                               Exit
+                                                       Case absotherchar
+                                                               If check < 0 Then Exit Else check = 0
+                                                               If depth Then
+                                                                       depth:-1
+                                                               Else
+                                                                       style[MATCHING].format(textarea, othercharpos, 1)
+                                                                       currentbrackets[1] = othercharpos
+                                                                       UnlockTextArea textarea
+                                                                       Return
+                                                               EndIf
+                                                       Case Asc("~n")
+                                                               If (otherchar/absotherchar) > 0 Then
+                                                                       If check = 2 Then check = 0 Else Exit
+                                                               Else
+                                                                       If check < 0 Then Exit Else check = -2
+                                                               EndIf
+                                                       Case Asc(".")   
+                                                               check:+1
+                                                       Default
+                                                               If check < 0 Then Exit Else check = 0
+                                                               If lsrc[othercharpos] = lsrc[currentcharpos] Then depth:+1
+                                               EndSelect
+                                       EndIf
+                                       
+                                       othercharpos:+(otherchar/absotherchar)
+                                       
+                               Wend
+                               
+                               UnlockTextArea textarea
+                               
+                       EndIf
+                       
+               EndIf
+               
+       EndMethod
+       
+       Method AutoIndent()
+               Local   p,q
+               Local c = TextAreaCursor(textarea,TEXTAREA_CHARS)
+               Local n = TextAreaSelLen(textarea,TEXTAREA_CHARS)
+               If c<cleansrc.length
+                       p=cleansrc.FindLast(EOL,cleansrc.length-(c-1))+1
+                       q=p
+                       While cleansrc[q]=9 And q<c
+                               q:+1
+                       Wend
+                       If q>c q=c
+               EndIf
+               SetTextAreaText textarea,EOL$+cleansrc[p..q],c,n
+               SelectTextAreaText textarea,c+1+q-p,0                   
+               UpdateCursor
+               UpdateCode
+       End Method
+       
+       Method IndentCode()
+               Local   a$
+' blockindent
+               Local p0 = TextAreaCursor(textarea,TEXTAREA_LINES)
+               Local p1 = TextAreaSelLen(textarea,TEXTAREA_LINES)
+' v122: make sure the entire block is selected (start cursor pos may in the middle of the line)
+               SelectTextAreaText textarea , p0 , p1 , TEXTAREA_LINES
+               UpdateCursor
+               For Local i:Int = 0 Until p1
+                       a$="~t"+TextAreaText(textarea,p0+i,1,TEXTAREA_LINES)
+                       SetTextAreaText textarea,a$,p0+i,1,TEXTAREA_LINES
+               Next
+               SelectTextAreaText textarea,p0,p1,TEXTAREA_LINES
+               UpdateCursor
+               UpdateCode
+       End Method
+
+       Method OutdentCode()
+               Local   a$,modified
+' blockoutdent
+               Local p0 = TextAreaCursor(textarea,TEXTAREA_LINES)
+               Local p1 = TextAreaSelLen(textarea,TEXTAREA_LINES)
+' v122: make sure the entire block is selected (start cursor pos may in the middle of the line)
+               SelectTextAreaText textarea , p0 , p1 , TEXTAREA_LINES
+               UpdateCursor
+               For Local i:Int = 0 Until p1
+                       a$=TextAreaText(textarea,p0+i,1,TEXTAREA_LINES)
+                       If a[0]=9 a$=a$[1..];modified=True
+                       SetTextAreaText textarea,a$,p0+i,1,TEXTAREA_LINES
+               Next
+               If Not modified
+                       For Local i:Int = 0 Until p1
+                               a$=TextAreaText(textarea,p0+i,1,TEXTAREA_LINES)
+                               If a[0]=32 a$=a$[1..]
+                               SetTextAreaText textarea,a$,p0+i,1,TEXTAREA_LINES
+                       Next    
+               EndIf
+               SelectTextAreaText textarea,p0,p1,TEXTAREA_LINES
+               UpdateCursor
+               UpdateCode
+       End Method
+
+       Function FilterKey(event:TEvent,context:Object)
+'              If event.id<>EVENT_KEYCHAR Return 1
+               Local id=event.id
+               Local key=event.data
+               Local mods=event.mods
+               Local this:TOpenCode=TOpenCode(context)
+?MacOS
+               If key=25 And mods=MODIFIER_SHIFT key=KEY_TAB
+?
+               If id=EVENT_KEYCHAR And this And key=KEY_TAB And TextAreaSelLen( this.textarea,TEXTAREA_CHARS )
+                       Select mods
+                               Case MODIFIER_NONE
+                                       this.IndentCode
+                               Case MODIFIER_SHIFT
+                                       this.OutdentCode
+                       End Select
+                       Return 0
+               EndIf
+
+               If id=EVENT_KEYDOWN And key=KEY_ENTER And this And this.host.options.autoindent
+                       this.AutoIndent()
+                       Return 0
+               EndIf
+               
+               Return 1
+       End Function
+
+       Method OnEvent()
+               Select EventSource()
+                       Case textarea
+                               Select EventID()
+                                       Case EVENT_GADGETMENU
+                                               PopupWindowMenu host.window,editmenu
+                                       Case EVENT_GADGETACTION
+                                               UpdateCode
+                                       Case EVENT_GADGETSELECT
+                                               UpdateCursor
+                               End Select
+               End Select
+       End Method
+                       
+       Method SetDirty( bool )
+               If dirty=bool Return
+               dirty=bool
+               name=StripDir(path)
+               If (dirty) name:+"*"
+               If (host.lockedpanel=Self) name=LocalizeString("{{tab_locked:%1}}").Replace("%1",name)
+               host.RefreshPanel Self
+               PollSystem
+       End Method
+       
+       Method SetLocked( bool )
+               Local locked:TOpenCode = TOpenCode(host.lockedpanel)
+               If locked And locked<>Self locked.SetLocked False
+               name=StripDir(path)
+               If (dirty) name:+"*"
+               If (bool)
+                       name=LocalizeString("{{tab_locked:%1}}").Replace("%1",name)
+                       host.lockedpanel=Self
+               Else
+                       host.lockedpanel=Null
+               EndIf
+               host.RefreshPanel Self
+       End Method
+       
+       Method Help()
+               If Not host.quickhelp Return
+               Local p = TextAreaCursor(textarea,TEXTAREA_CHARS)
+               Local a$ = WordAtPos(cleansrc,p)
+               If a=helpcmd
+                       Local l$ = host.quickhelp.link(a$)
+                       If l
+                               host.helppanel.go host.bmxpath+l$
+                       EndIf
+               Else
+                       helpcmd=a$
+                       helpstring$=host.quickhelp.help(a$)
+                       UpdateStatus    'host.setstatus helpstring$
+               EndIf
+       End Method
+
+       Method Find()
+               host.findreq.ShowFind WordAtPos(cleansrc,TextAreaCursor(textarea,TEXTAREA_CHARS))
+       End Method
+               
+       Method FindNext(s$)
+               If s seek=s Else s=seek
+               Local p = TextAreaCursor(textarea,TEXTAREA_CHARS)
+               p:+TextAreaSelLen(textarea,TEXTAREA_CHARS)
+' case insensitive
+               Local l$ = s.toLower()
+               p=cleansrcl.Find(l$,p)
+               If p=-1 p=cleansrcl.Find(l$)
+' case sensitive
+'              p=cleansrc.Find(s$,p+1)
+'              if p=-1 p=cleansrc.Find(s$)
+               If p=-1
+                       Notify LocalizeString("{{find_notification_cannotfind}}").Replace("%1",s)
+                       Return False
+               Else
+                       SelectTextAreaText textarea,p,Len s,TEXTAREA_CHARS
+                       UpdateCursor
+                       Return True
+               EndIf
+       End Method
+
+       Method ReplaceAll(s$,r$)
+               Local t$ = TextAreaText( textarea ).ToLower()
+               Local c = TextAreaCursor(textarea,TEXTAREA_CHARS),i,p
+               s = s.ToLower()
+               Repeat
+                       Local i2=t.Find( s,i )
+                       If i2=-1 Exit
+                       p:+i2-i
+                       i=i2+s.length
+                       SelectTextAreaText textarea,p,s.length
+                       UpdateCursor
+                       UpdateCode              
+                       SetTextAreaText textarea,r,p,s.length
+                       If p<c c=c+r.length-s.length                    
+                       p:+r.length
+                       SelectTextAreaText textarea,p,0
+                       UpdateCursor
+                       UpdateCode
+               Forever
+               SelectTextAreaText textarea,c,0
+               UpdateCursor
+       End Method
+       
+       Method FindReplace(r$)
+               Local n, f$, x$
+               Local p = r.Find("~0")
+               If p>0
+                       f$=r[..p]
+                       r$=r[p+1..]
+                       ReplaceAll f$,r$
+               Else
+                       p=TextAreaCursor(textarea,TEXTAREA_CHARS)
+                       n=TextAreaSelLen(textarea,TEXTAREA_CHARS)
+                       If Not n Return
+                       SetTextAreaText textarea,r$,p,n
+                       SelectTextAreaText textarea,p+r.length,0
+                       UpdateCursor
+                       UpdateCode              
+               EndIf
+               Return True
+       End Method
+       
+       Method ReadSource(path$)
+               Local   src$            
+               src=CacheAndLoadText(path)
+               src=src.Replace(Chr(13),"")
+               src=src.Replace(Chr(11),"")
+               LockTextArea textarea
+               SetTextAreaText textarea,src
+               UnlockTextArea textarea
+               filesrc=TextAreaText(textarea)
+               cleansrc=""
+               cleansrcl=""
+               ActivateGadget textarea         
+       End Method
+       
+       Method SaveSource(file$)
+               If host.options.autobackup
+                       DeleteFile file+".bak"
+                       RenameFile file,file+".bak"
+               EndIf
+               Local   src$ = TextAreaText(textarea)
+               filesrc=src
+               src=src.Replace(Chr(13),Chr(10))
+               src=src.Replace(Chr(11),"")
+               Local txt$ = src.Replace$(Chr(10),Chr(13)+Chr(10))              
+
+               Try
+                       SaveText txt,file
+               Catch exception:Object
+                       Local err$=String(exception)
+                       Notify "Save Error~n"+err
+                       Return False
+               EndTry
+
+               path=host.FullPath$(file)
+               dirty=True
+               SetDirty False
+               host.AddRecent(path$)
+               Return True
+       End Method
+
+       Method BuildSource(quick,debug,threaded,gui,run)
+               Local cmd$,out$,arg$            
+               If isbmx Or isc Or iscpp
+                       cmd$=quote(host.bmkpath)
+                       cmd$:+" makeapp"
+                       If run cmd$:+" -x"
+                       If debug cmd$:+" -d" Else cmd$:+" -r"   '-v
+                       If threaded cmd$:+" -h"
+                       If gui cmd$:+" -t gui"
+                       If Not quick cmd$:+" -a"
+                       If debug Or threaded
+                               out=StripExt(host.FullPath(path))
+                               If debug out:+".debug"
+                               If threaded out:+".mt"
+                               cmd:+" -o "+quote(out$)+" "
+                       EndIf           
+                       cmd$:+" "+quote(host.FullPath(path))
+                       If run
+                               arg$=host.GetCommandLine()
+                               If arg cmd$:+" "+arg
+                       EndIf
+                       host.execute cmd,"Building "+StripExt(StripDir(path))   ',exe$
+               Else
+                       If ishtml
+                               host.helppanel.Go "file://"+path
+                       Else
+'see what the system shell thinks of the file
+                               Local cd$=CurrentDir()
+                               ChangeDir ExtractDir(path)
+                               cmd=StripDir(path)
+                               host.execute cmd,"Building "+cmd
+                               ChangeDir cd
+                       EndIf                   
+               EndIf
+'              print cmd
+       End Method
+       
+       Method Save()
+               Local   file$ = path
+               If host.IsTempPath(path)
+                       file=RequestFile(LocalizeString("{{request_saveas_title}}"),FileTypeFilters,True,"")
+                       If file="" Return False
+                       If ExtractExt(file)="" file=file+".bmx"
+                       dirty=True
+               EndIf
+               If dirty SaveSource(file)
+               Return True
+       End Method
+' common command interface
+
+       Method Invoke(command,argument:Object=Null)
+               Local   file$,ex$
+               Local   p,res
+               Select command
+                       Case TOOLSHOW
+                               host.SetCodeNode GetNode()
+                               host.SetTitle path                              
+' simon was here                               If textarea Edit
+                               If textarea ActivateGadget textarea
+
+                       Case TOOLCLOSE
+                               If dirty 'Or host.IsTempPath(path)
+                                       Invoke(TOOLSHOW)
+                                       p=Proceed(LocalizeString("{{request_savechanges}}").Replace("%1",name)) 'the current file?
+                                       If p=-1 Return True
+                                       If p=1
+                                               If Not Save() Return True
+                                       EndIf
+                               EndIf
+                               If codenode Then
+                                       codenode.Free()
+                                       codenode=Null
+                               EndIf
+                               'Added just in case MaxGUI driver doesn't handle properly.
+                               SetGadgetFilter textarea,Null,Null
+                               'Seb gone.
+                               host.RemovePanel Self
+                               FreeGadget(editmenu)
+                       Case TOOLSAVE
+                               Save
+                       Case TOOLQUICKSAVE
+                               file=path
+                               If dirty SaveSource(file)
+                       Case TOOLSAVEAS
+                               file=path
+                               If host.IsTempPath(path) file$=""
+                               file=RequestFile(LocalizeString("{{request_saveas_title}}"),FileTypeFilters,True,file)
+                               If file="" Return
+                               ex$=ExtractExt(file)
+                               If ex$=""
+                                       file=file+".bmx"
+                                       isbmx=True
+                               Else
+                                       isbmx=(ex.ToLower()="bmx")
+                                       ishtml=(ex.ToLower()="html")
+                                       isc=(ex.ToLower()="c")
+                                       iscpp=(ex.ToLower()="cpp" Or ex.ToLower()="cxx")
+                               EndIf                           
+                               SaveSource(file$)
+                               RefreshStyle()
+                               GetNode().Refresh
+                               SetDirty False
+                               host.SetTitle path
+                       Case TOOLGOTO
+                               Local line=Int(String(argument))
+                               SelectTextAreaText textarea,line-1,0,TEXTAREA_LINES                             
+                               UpdateCursor
+                               ActivateGadget textarea         
+                       Case TOOLFIND
+                               Find
+                       Case TOOLFINDNEXT
+                               Return FindNext(String(argument))
+                       Case TOOLREPLACE
+                               Return FindReplace(String(argument))    
+                       Case TOOLBUILD
+                               BuildSource host.quickenabled,host.debugenabled,host.threadedenabled,host.guienabled,False
+                       Case TOOLRUN
+                               BuildSource host.quickenabled,host.debugenabled,host.threadedenabled,host.guienabled,True
+                       Case TOOLLOCK
+                               SetLocked True
+                       Case TOOLUNLOCK
+                               SetLocked False                 
+                       Case TOOLHELP
+                               Help()
+                       Case TOOLUNDO
+                               Undo()
+                       Case TOOLREDO
+                               Redo()
+                       Case TOOLREFRESH
+                               RefreshStyle()
+                       Case TOOLCUT
+                               GadgetCut textarea
+                               UpdateCursor()
+                               UpdateCode()
+                       Case TOOLCOPY
+                               GadgetCopy textarea
+                       Case TOOLPASTE
+                               GadgetPaste textarea
+                               UpdateCursor()
+                               UpdateCode()
+                       Case TOOLSELECTALL
+                               SelectTextAreaText textarea
+                               UpdateCursor()
+                       Case TOOLINDENT
+                               IndentCode()
+                       Case TOOLOUTDENT
+                               OutdentCode()
+                       Case TOOLPRINT
+                               GadgetPrint textarea
+               End Select
+       End Method
+               
+       Function CreateEditMenu:TGadget()
+               Local   edit:TGadget = CreateMenu("{{popup_edit}}",0,Null)
+               CreateMenu "{{popup_edit_quickhelp}}",MENUQUICKHELP,edit
+               CreateMenu "",0,edit
+               CreateMenu "{{popup_edit_cut}}",MENUCUT,edit
+               CreateMenu "{{popup_edit_copy}}",MENUCOPY,edit
+               CreateMenu "{{popup_edit_paste}}",MENUPASTE,edit
+               CreateMenu "",0,edit
+               CreateMenu "{{popup_edit_selectall}}",MENUSELECTALL,edit
+               CreateMenu "",0,edit
+               CreateMenu "{{popup_edit_blockindent}}",MENUINDENT,edit
+               CreateMenu "{{popup_edit_blockoutdent}}",MENUOUTDENT,edit
+               CreateMenu "",0,edit
+               CreateMenu "{{popup_edit_find}}",MENUFIND,edit
+               CreateMenu "{{popup_edit_findnext}}",MENUFINDNEXT,edit
+               CreateMenu "{{popup_edit_replace}}",MENUREPLACE,edit
+               CreateMenu "{{popup_edit_goto}}",MENUGOTO,edit
+               Return edit
+       End Function
+       
+       Method MakePathTemp()
+' prepends "." to file name with code borrowed from SaveAs             
+               Local file$=ExtractDir(path)+"/."+StripDir(path)
+               SaveSource(file$)
+'              Refresh
+               GetNode().Refresh
+'              setdirty False
+               host.SetTitle path
+       End Method
+       
+       Function Create:TOpenCode(path$,host:TCodePlay)
+               Local   code:TOpenCode
+               Local   stream:TStream
+               Local   isnew
+               If path
+                       If FileType(path)<>FILETYPE_FILE
+                               Return Null
+                       EndIf
+                       stream=ReadFile(path)
+                       If Not stream
+'                              Notify "Open could not read from "+path         
+                               Return Null
+                       EndIf
+                       CloseFile stream
+               Else
+                       TEMPCOUNT:+1
+                       path=host.bmxpath+"/tmp/untitled"+TEMPCOUNT+".bmx"
+                       isnew=True
+               EndIf
+               code=New TOpenCode
+               code.host=host
+               code.active=True
+               code.path=host.FullPath(path)
+               code.editmenu=CreateEditMenu()
+               codeplay.addpanel(code)
+               code.textarea=CreateTextArea(0,0,ClientWidth(code.panel),ClientHeight(code.panel),code.panel,0)
+               DelocalizeGadget code.textarea
+               SetGadgetFilter code.textarea,code.FilterKey,code
+               SetTextAreaText code.textarea,"~n"
+               SetGadgetLayout code.textarea,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+               code.RefreshStyle()
+               
+               If isnew
+                       code.SaveSource path
+                       code.filesrc="~n"
+                       ActivateGadget code.textarea
+               Else
+                       host.UpdateProgress "Reading Stream"
+                       code.ReadSource(path)
+               EndIf
+               
+               If ExtractExt(path).toLower()="bmx" code.isbmx=True
+               If ExtractExt(path).toLower()="c" code.isc=True
+               If ExtractExt(path).toLower()="cpp" code.iscpp=True
+               If ExtractExt(path).toLower()="cxx" code.iscpp=True
+               If ExtractExt(path).toLower()="html" code.ishtml=True
+               If ExtractExt(path).toLower()="htm" code.ishtml=True
+               code.UpdateCode False
+               code.filesrc=TextAreaText(code.textarea)
+               Return code
+       End Function
+
+End Type
+
+Type TRect
+       Field           x,y,w,h
+
+       Method Set(xpos,ypos,width,height)
+               x=xpos;y=ypos;w=width;h=height
+       End Method
+       
+       Method ToString$()
+               Return ""+x+","+y+","+w+","+h
+       End Method
+
+       Method FromString(s$)
+               Local   p,q,r
+               p=s.Find(",")+1;If Not p Return
+               q=s.Find(",",p)+1;If Not q Return
+               r=s.Find(",",q)+1;If Not r Return
+               x=Int(s[..p-1])
+               y=Int(s[p..q-1])
+               w=Int(s[q..r-1])
+               h=Int(s[r..])
+       End Method
+       
+       Method IsOutside(tx,ty,tw,th)
+               If x+w<=tx Or y+h<=ty Return True
+               If x>=tx+tw Or y>=ty+th Return True     
+       End Method
+
+End Type
+
+Type TCodePlay
+
+       Const EDITMODE=1
+       Const DEBUGMODE=2
+       
+       Field bmxpath$,bmkpath$
+       Field panels:TToolPanel[]
+       Field helppanel:THelpPanel
+       Field currentpanel:TToolPanel
+       Field output:TOutputPanel
+       Field lockedpanel:TToolPanel
+       Field activepanel:TToolPanel
+       
+       Field cmdlinereq:TCmdLineRequester
+       Field cmdline$
+       'Field syncmodsreq:TSyncModsRequester
+       Field gotoreq:TGotoRequester
+       Field findreq:TFindRequester
+       Field replacereq:TReplaceRequester
+       Field options:TOptionsRequester
+'      Field progress:TProgressRequester
+       Field activerequesters:TList = New TList
+       Field projectreq:TProjectRequester
+       Field projectprops:TProjectProperties
+       Field searchreq:TSearchRequester
+       Field aboutreq:TAboutRequester
+       
+       
+       Field eventhandlers:TList=New TList
+       Field window:TGadget,menubar:TGadget,toolbar:TGadget,client:TGadget,tabbar:TGadget
+       Field split:TSplitter
+       Field debugtree:TDebugTree
+       
+       Field root:TNode
+       Field helproot:TNode
+       Field projects:TProjects
+       Field coderoot:TNode
+       Field navbar:TNavBar    
+
+       Field mode
+       Field debugcode:TOpenCode
+
+       Field quickenable:TGadget,quickenabled  'menu,state
+       Field debugenable:TGadget,debugenabled  'menu,state
+       Field threadedenable:TGadget,threadedenabled
+       Field guienable:TGadget,guienabled              'menu,state
+       Field quickhelp:TQuickHelp
+       Field running
+       Field recentmenu:TGadget
+       Field recentfiles:TList=New TList
+       Field recentmenus:TGadget[]
+       Field openlist:TList=New TList
+       Field openlock$
+       Field projlist:TList=New TList
+       Field winsize:TRect=New TRect
+       Field winmax,tooly,splitpos,debugview,navtab
+       Field progress,splitorientation
+
+?MacOS 
+       Method RanlibMods()
+
+               Local cmd$=Quote( bmxpath+"/bin/bmk" )+" ranlibdir "+Quote( bmxpath+"/mod" )
+               system_ cmd
+
+       End Method
+?
+
+       Method CheckVersion$()
+               Local   process:TProcess
+               Local   bytes:Byte[]
+               Local   cmd$,version$
+
+               cmd$=bmxpath+"/bin/bcc"
+               
+?win32
+               cmd:+".exe"
+?
+               
+               cmd=Quote(cmd)
+               process=CreateProcess(cmd$,HIDECONSOLE)
+               If process
+                       Repeat
+                               Delay 10
+                               bytes=process.pipe.ReadPipe()
+                               If bytes
+                                       version:+String.FromBytes(bytes,bytes.length)
+                               EndIf
+                       Until Not process.Status()
+               EndIf
+
+               If version=""
+                       Notify "Unable to determine BlitzMax version.~n~nPlease reinstall BlitzMax to repair this problem."
+                       End
+               EndIf
+               
+               BCC_VERSION=version.Trim()
+               
+'              print "bcc version="+version
+
+               If version.find("(expired)")>-1 'Demo timed out
+                       Notify "This demo version of BlitzMax has expired.~n~nPlease visit www.blitzbasic.com to buy the full version."
+                       End
+               EndIf
+
+               If version.find("Demo Version")>-1      'Valid demo version
+                       is_demo=True
+                       Notify version+"~nTo purchase the full version please visit www.blitzbasic.com."
+                       Notify ABOUTDEMO
+               EndIf
+               
+       End Method
+       
+       Method OpenProgress(message$)
+'              progress.Open message
+               DisableGadget window
+               SetStatus message
+               progress=-1
+       End Method
+
+       Method CloseProgress()
+'              progress.Hide
+               SetStatus ""
+               EnableGadget window
+               progress=0
+       End Method
+       
+       Method UpdateProgress(message$,value=0)         'returns false if cancelled
+'              Return progress.Update(message,value)
+               If progress
+                       If progress/5<>value/5
+                               SetStatus message+" "+value+"%"
+                               progress=value
+'                              Pollsystem
+                       EndIf
+               EndIf
+       End Method
+
+       Method FullPath$(path$)
+               If path[..8]="$BMXPATH" path=bmxpath+path[8..]
+               If Not path.Contains("::") Then path = RealPath(path)
+?win32
+               path=path.Replace("\","/")
+?
+               Return path
+       End Method
+
+       Method IsTempPath(path$)
+               If path[..bmxpath.length+5]=bmxpath+"/tmp/" Return True
+       End Method
+       
+       Method AddDefaultProj(p$)
+               Local projdata:TList = New TList
+               projdata.AddLast p
+               projlist.AddLast projdata
+       End Method
+
+       Method ReadConfig()
+               Local   stream:TStream
+               Local   f$,p,a$,b$
+' defaults             
+               Local wh=GadgetHeight(Desktop())-80'32
+               Local ww=wh
+               Local wx=(GadgetWidth(Desktop())-ww)/2
+               Local wy=(GadgetHeight(Desktop())-wh)/2
+               winsize.set( wx,wy,ww,wh )
+               quickenabled=False
+               debugenabled=True
+               threadedenabled=False
+               guienabled=True 
+               splitpos=200;splitorientation = SPLIT_VERTICAL
+' read ini
+               stream=ReadFile(bmxpath+"/cfg/ide.ini")
+               If Not stream
+                       AddDefaultProj "Samples|samples"
+                       If Not is_demo
+                               AddDefaultProj "Modules Source|mod"
+                               AddDefaultProj "BlitzMax Source|src"
+                       EndIf
+                       Return
+               EndIf
+               options.read(stream)            
+               options.Snapshot
+
+               Local projdata:TList
+               
+               While Not stream.Eof()
+                       f$=stream.ReadLine()
+                       p=f.find("=")
+                       If p=-1 Continue
+                       a$=f[..p]
+                       b$=f[p+1..]
+                       Select a$
+                               Case "ide_version"
+                               
+                               Case "file_recent"
+                                       recentfiles.addlast b$
+                               Case "file_open"
+                                       openlist.addlast b$
+                               Case "prg_quick"
+                                       quickenabled=Int(b$)
+                               Case "prg_debug"
+                                       debugenabled=Int(b$)
+                               Case "prg_threaded"
+                                       threadedenabled=Int(b$)
+                               Case "prg_gui"
+                                       guienabled=Int(b$)
+                               Case "cmd_line"
+                                       cmdline=b$
+                               Case "prg_locked"
+                                       openlock=b$
+                               Case "win_size"
+                                       winsize.FromString(b$)
+                               Case "win_max"
+                                       winmax=Int(b$)
+                               Case "split_position"
+                                       splitpos=Int(b$)
+                               Case "split_orientation"
+                                       splitorientation=Int(b$)
+                               Case "proj_node"
+                                       projdata=New TList
+                                       projdata.AddLast b
+                                       projlist.AddLast projdata
+                               Case "proj_data"
+                                       If projdata projdata.AddLast b
+                               'Case "sync_state"
+                                       'syncmodsreq.FromString b$
+                       End Select
+               Wend
+               stream.close()          
+       End Method
+       
+       Method WriteConfig()
+               Local   panel:TToolPanel
+               Local   node:TNode
+               Local   f$
+               
+               Local   stream:TStream = WriteFile(bmxpath+"/cfg/ide.ini")
+               If Not stream Return
+' options
+               options.write(stream)
+' defaults             
+               stream.WriteLine "[Defaults]"
+               stream.WriteLine "ide_version="+IDE_VERSION$
+               stream.WriteLine "prg_quick="+quickenabled
+               stream.WriteLine "prg_debug="+debugenabled
+               stream.WriteLine "prg_threaded="+threadedenabled
+               stream.WriteLine "prg_gui="+guienabled
+               stream.WriteLine "win_size="+winsize.ToString()
+               stream.WriteLine "win_max="+winmax
+               stream.WriteLine "split_position="+SplitterPosition(split)
+               stream.WriteLine "split_orientation="+SplitterOrientation(split)
+               stream.WriteLine "cmd_line="+cmdline
+               'stream.WriteLine "sync_state="+syncmodsreq.ToString()
+               If lockedpanel stream.WriteLine "prg_locked="+lockedpanel.path
+               For f$=EachIn recentfiles
+                       stream.WriteLine "file_recent="+f$
+               Next
+               For Local panel:TToolPanel = EachIn panels
+                       f$=panel.path
+                       If f$ And Not IsTempPath(f$) stream.WriteLine "file_open="+f$
+               Next
+               projects.write(stream)  
+               stream.close
+       End Method
+       
+       Method CloseAll(dontask,inccurrent=True)        'returns true if successful
+               Local   count, cancel
+               For Local panel:TToolPanel = EachIn panels
+                       If TOpenCode(panel) And (inccurrent Or currentpanel <> panel) count:+1
+               Next
+               If (Not count) Or dontask Or Confirm(LocalizeString("{{request_closeall}}"))
+                       For Local panel:TToolPanel = EachIn panels[..]  'Use a copy of the original array for iterating.
+                               If (inccurrent Or currentpanel <> panel) And panel.invoke(TOOLCLOSE) Then
+                                       cancel=True
+                                       Exit
+                               EndIf
+                       Next
+                       Return Not cancel
+               EndIf
+       End Method
+
+       Method Quit()
+               WriteConfig()
+               If CloseAll(True) running=False
+       End Method
+
+       Method DebugExit()
+               If debugcode
+                       debugtree.cancontinue = False
+                       debugcode.Edit          'restore cursor etc.    
+                       debugcode=Null
+               EndIf
+               SetMode EDITMODE
+               RefreshToolbar()
+       End Method
+               
+       Method DebugSource(path$,line,column)
+               Local   code:TOpenCode
+               path=FullPath(path)
+               code=OpenSource(path)
+               If Not code Then
+                       Notify(LocalizeString("{{loaderror_failed}}").Replace("%1",path), True)
+                       Return
+               EndIf
+               If debugcode And debugcode<>code Then debugcode.Edit()  'restore cursor etc.
+               debugcode=code
+               debugcode.debug(line,column)    
+               ActivateWindow window
+               PollSystem
+       End Method
+       
+       Method SetMode(m)
+               If mode=m Return
+               ActivateWindow window
+               Select m
+               Case DEBUGMODE
+                       navtab=navbar.SelectedView()
+                       navbar.SelectView debugview
+               Case EDITMODE
+                       navbar.SelectView navtab
+               End Select
+               mode=m
+               RefreshToolbar
+       End Method
+       
+       Method RefreshMenu()
+               TOpenCode.RefreshHighlightingMsg()
+               UpdateWindowMenu window
+       EndMethod
+       
+       Method RefreshToolbar()
+               Local   i
+' sourceedit buttons
+               If THelpPanel(CurrentPanel)
+                       DisableGadgetItem toolbar,TB_CLOSE
+               Else
+                       EnableGadgetItem toolbar,TB_CLOSE
+               EndIf
+               If TOpenCode(CurrentPanel)
+                       EnableGadgetItem toolbar,TB_SAVE
+                       For i=TB_CUT To TB_FIND
+                               EnableGadgetItem toolbar,i
+                       Next
+               Else
+                       DisableGadgetItem toolbar,TB_SAVE
+                       For i=TB_CUT To TB_FIND
+                               DisableGadgetItem toolbar,i
+                       Next                    
+               EndIf
+' debug buttons
+               If mode = DEBUGMODE And debugtree.cancontinue Then
+                       If GadgetItemIcon( toolbar, TB_BUILDRUN ) = TB_BUILDRUN Then
+                               ModifyGadgetItem( toolbar, TB_BUILDRUN, "", GADGETITEM_LOCALIZED, TB_CONTINUE, "{{tb_continue}}" )
+                       EndIf
+               Else
+                       If GadgetItemIcon( toolbar, TB_BUILDRUN ) <> TB_BUILDRUN Then
+                               ModifyGadgetItem( toolbar, TB_BUILDRUN, "", GADGETITEM_LOCALIZED, TB_BUILDRUN, "{{tb_buildrun}}" )
+                       EndIf
+               EndIf
+               For i=TB_STEP To TB_STEPOUT
+                       If mode=DEBUGMODE And debugtree.cancontinue Then
+                               EnableGadgetItem toolbar,i
+                       Else
+                               DisableGadgetItem toolbar,i
+                       EndIf
+               Next
+' stop button          
+               If output And output.process
+                       EnableGadgetItem toolbar,TB_STOP
+               Else
+                       DisableGadgetItem toolbar,TB_STOP
+               EndIf           
+       End Method
+       
+       Method IsSourceOpen(path$)
+               Local   p$ = FullPath(path)
+               For Local panel:TToolPanel = EachIn panels
+                       If panel.path=p Return True
+               Next
+       End Method
+       
+       Method OpenSource:TOpenCode(path$)
+               Local   code:TOpenCode
+               Local   ext$,p$
+               If path$="."
+                       path$=RequestFile(LocalizeString("{{request_openfile}}"),FileTypeFilters )
+                       If path$="" Return
+               EndIf
+' check if already open
+               p$=FullPath(path).ToLower()
+               For Local panel:TToolPanel = EachIn panels
+                       If panel.path.ToLower()=p
+                               SelectPanel panel
+                               Return TOpenCode(panel)
+                       EndIf
+               Next
+' open based on extension              
+'              Select ExtractExt(Upper(path$))
+'              Case "BMX","TXT","BB","CPP","C","S","I","H","HTML","CSS","BAT","FS","VS","README",""
+                       OpenProgress LocalizeString("{{msg_loading}}").Replace("%1",StripDir(path))
+                       code=TOpenCode.Create(path,Self)
+                       If code
+                               AddRecent code.path
+                       EndIf
+                       CloseProgress
+                       If code
+                               ActivateGadget code.textarea
+                               code.GetNode().Refresh
+                       EndIf
+                       Return code
+'              end select
+       End Method
+       
+       Method AddRecent(path$)
+               For Local f$ = EachIn recentfiles
+                       If f$=path$ recentfiles.Remove(f$);Exit
+               Next
+               recentfiles.AddFirst(path$)
+               RefreshRecentFiles
+               UpdateWindowMenu window
+       End Method
+       
+       Method RefreshRecentFiles()
+               Local   n
+               For Local m:TGadget = EachIn recentmenus
+                       FreeMenu m
+               Next
+               n=Min(recentfiles.count(),16)
+               recentmenus=New TGadget[n]
+               n=0
+               For Local f$ = EachIn recentfiles
+                       recentmenus[n]=CreateMenu(f$,MENURECENT+n,recentmenu)
+                       n:+1
+                       If n=16 Exit
+               Next
+       End Method
+       
+       Method BuildModules(buildall)
+               Local cmd$,out$,exe$
+               output.Stop
+               SaveAll
+               cmd$=quote(bmkpath)
+               cmd$:+" makemods "
+               
+               If buildall cmd$:+"-a "
+               If threadedenabled cmd:+"-h "
+               
+               Execute cmd,LocalizeString("{{output_msg_buildingmods}}")
+       End Method
+
+       Method ImportBB()
+               Local f$ = RequestFile(LocalizeString("{{request_importbb_title}}"),"bb" )
+               If Not f$ Return
+               Local cmd$ = Quote(bmkpath$)
+               cmd$:+" convertbb "
+               cmd$:+quote(FullPath(f$))
+               Execute cmd,LocalizeString("{{output_msg_converting}}").Replace("%1",StripExt(StripDir(f$)))
+               output.wait
+               OpenSource(StripExt(f$)+".bmx")
+       End Method
+
+       Method GetCommandLine$()
+               Return cmdline
+       End Method
+
+       Method SetCommandLine(text$)
+               cmdline=text
+       End Method
+       
+       Method SetStatus(text$)
+               SetStatusText window,text
+       End Method
+
+       Method Execute(cmd$,mess$="",post$="",home=True,tool:TTool=Null)
+               If Not output output=TOutputPanel.Create(Self)
+               output.execute cmd$,mess$,post$,home,tool
+       End Method
+
+       Method SelectError(path$,column,line)
+               Local   panel:TOpenCode,found
+               For panel=EachIn panels
+                       If panel.path=path found=True;Exit
+               Next
+               If Not found panel=OpenSource(path)
+               If panel
+                       SelectPanel panel
+                       panel.Debug line,column
+               EndIf
+       End Method
+       
+       Method ParseError(err$)
+               Local           mess$,file$,p,q
+               Local           line,column
+' bcc error
+               If err$[..13]="Compile Error"
+                       err=err[14..]
+                       p=err.find(EOL$)
+                       If p=-1 p=err.length
+                       mess=err[..p]
+                       err=err[p+1..]
+                       If err[..1]="["
+                               p=err.find("]")
+                               If p=-1 p=err.length
+                               file$=err[1..p]
+                               p=file.find(";")+1
+                               If p=0 p=err.length
+                               q=file.find(";",p)+1
+                               If q=0 q=err.length
+                               line=Int(file[p..q-1])
+                               column=Int(file[q..])
+                               file=FullPath(file[..p-1])                              
+                               SelectError file,column,line
+                       EndIf
+                       Notify LocalizeString("{{output_error_compileerror}}").Replace("%1",mess)
+                       SetStatus mess
+                       Return
+               EndIf
+' gcc error
+               err=err.Replace(EOL+"   "," ")
+               While err
+                       p=err.find(EOL)
+                       If p=-1 p:+err.length   'equiv. to p=err.length-1 ;-)
+                       mess=err[..p]
+                       err=err[p+1..]
+                       p=0
+                       Repeat
+                               p=mess.Find(":",p)+1
+                               If p=0 Exit
+                               q=mess.Find(":",p)
+                               If q<>-1
+                                       file=mess[..p-1]
+                                       line=Int(mess[p..q])
+                                       If line
+                                               mess=mess[q+1..]
+                                               SelectError file,column,line
+                                               Notify LocalizeString("{{output_error_compileerror}}").Replace("%1",mess)
+                                               Return
+                                       EndIf
+                                       p=q+1
+                               EndIf
+                       Forever
+               Wend
+       End Method
+               
+       Method AddPanel(tabpanel:TToolPanel)
+               Local   panel:TGadget,index
+               index=CountGadgetItems(tabbar)
+               If panels.length<=index panels=panels[..index+1]
+               AddGadgetItem(tabbar,tabpanel.name$,GADGETITEM_DEFAULT|GADGETITEM_LOCALIZED)
+               
+               panel=CreatePanel(0,0,ClientWidth(tabbar),ClientHeight(tabbar),tabbar,0)        'name           
+               SetGadgetLayout panel,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+               tabpanel.panel=panel
+               
+               tabpanel.index=index
+               panels[index]=tabpanel
+               SelectPanel tabpanel
+               AddHandler tabpanel
+       End Method
+
+       Method AddHandler(handler:TEventHandler)
+               eventhandlers.addlast handler
+       End Method
+
+       Method RemovePanel(tabpanel:TToolPanel)
+               Local p:TToolPanel[]
+               Local index
+               eventhandlers.remove tabpanel
+' unset debugcode
+               If debugcode=tabpanel debugcode=Null
+' activate next panel
+               If tabpanel=activepanel activepanel=helppanel
+               If tabpanel=lockedpanel lockedpanel=Null
+               If tabpanel=currentpanel
+                       index=tabpanel.index+1
+                       If index>=panels.length index=panels.length-2
+                       SelectPanel panels[index]
+               EndIf
+' remove from array
+               p=panels
+               panels=panels[..panels.length-1]
+               For index=tabpanel.index To panels.length-1
+                       panels[index]=p[index+1]
+                       panels[index].index=index
+               Next
+' remove gadget        - simon come here,  placing before remove needs fix in fltk
+               FreeGadget tabpanel.panel
+               RemoveGadgetItem tabbar,tabpanel.index
+               tabpanel.panel=Null
+       End Method
+               
+       Method HookRequester(req:TRequester)
+               If Not activerequesters.Contains(req) Then
+                       If req.IsModal() Then
+                               For Local tmpRequester:TRequester = EachIn activerequesters
+                                       DisableGadget tmpRequester.window
+                               Next
+                               DisableGadget window
+                       EndIf
+                       activerequesters.AddFirst(req)
+               EndIf
+       End Method
+       
+       Method UnhookRequester(req:TRequester)
+               If activerequesters.Contains(req) Then
+                       activerequesters.Remove(req)
+                       If req.IsModal() Then
+                               For Local tmpRequester:TRequester = EachIn activerequesters
+                                       EnableGadget tmpRequester.window
+                               Next
+                               EnableGadget window
+                       EndIf
+               EndIf
+       EndMethod
+       
+       Method SetTitle(title$="")
+               If title title=" - "+title
+               SetGadgetText window,"MaxIDE"+title
+       End Method
+       
+       Method SelectPanel(panel:TToolPanel)    
+               Local   curr:TToolPanel = currentpanel
+               currentpanel=panel
+               If curr And curr<>currentpanel
+                       SelectGadgetItem tabbar,panel.index
+                       ShowGadget panel.panel
+                       If panel.active activepanel=panel
+                       HideGadget curr.panel
+                       RefreshToolbar
+               EndIf
+               currentpanel.Invoke TOOLSHOW
+       End Method
+               
+       Method RefreshPanel(panel:TToolPanel)   'call after a name change
+               ModifyGadgetItem( tabbar,panel.index,panel.name,GADGETITEM_LOCALIZED )  
+       End Method
+
+       Function OutsideDesktop(winrect:TRect)
+               Local x,y,w,h
+               Local desk:TGadget = Desktop()
+               x=GadgetX(desk)
+               y=GadgetY(desk)
+               w=GadgetWidth(desk)
+               h=GadgetHeight(desk)
+               Return winrect.IsOutside(x,y,w,h)
+       End Function
+
+       Method SetCodeNode(code:TNode)
+               Local node:TNode
+               If coderoot.kids.count() node=TNode(coderoot.kids.First())
+               If node=code Return
+               If node node.Detach
+               If code
+                       coderoot.Append code
+                       coderoot.Refresh
+                       coderoot.Open
+                       code.Open
+               EndIf
+       End Method
+
+       Method Initialize()             
+               Local   open:TOpenCode, splash:TGadget
+               Local   dir$,nomods,pname$,p
+               Local   stream:TStream
+               
+               Try
+                       bmxpath=BlitzMaxPath()
+               Catch err$
+                       Notify "Unable to determine BlitzMax installation directory."
+                       End
+               EndTry
+
+               CreateDir bmxpath+"/tmp"
+               If FileType( bmxpath+"/tmp" )<>FILETYPE_DIR
+                       Notify "Unable to create BlitzMax 'tmp' directory."
+                       End
+               EndIf
+?Win32
+               CreateFile bmxpath+"/tmp/t.exe"
+               If FileType( bmxpath+"/tmp/t.exe" ) <> FILETYPE_FILE
+                       Notify "Unable to write to BlitzMax installation directory.~n"+..
+                       "Please run MaxIDE as administrator, or reinstall BlitzMax to a different directory."
+                       End
+               EndIf
+               DeleteFile bmxpath+"/tmp/t.exe"
+?
+               bmkpath=bmxpath+"/bin/bmk"
+?Win32
+               bmkpath:+".exe"
+?
+               dir$=bmxpath+"/mod"
+               If FileType(dir)=FILETYPE_NONE
+                       If Not CreateDir(dir)
+                               Notify "Failed to create %1 directory:~n%2".Replace("%1","Module").Replace("%2",dir)
+                               End
+                       EndIf
+                       nomods=True
+               EndIf
+               dir$=bmxpath+"/tmp"
+               If FileType(dir)=FILETYPE_NONE
+                       If Not CreateDir(dir)
+                               Notify "Failed to create %1 directory:~n%2".Replace("%1","Temp").Replace("%2",dir)
+                               End
+                       EndIf
+               EndIf
+               dir$=bmxpath+"/cfg"
+               If FileType(dir)=FILETYPE_NONE
+                       If Not CreateDir(dir)
+                               Notify "Failed to create %1 directory:~n%2".Replace("%1","Config").Replace("%2",dir)
+                               End
+                       EndIf
+               EndIf
+               
+               CheckVersion()
+               
+               splash=CreateWindow("MaxIDE",200,200,400,140,Null,WINDOW_CLIENTCOORDS|WINDOW_HIDDEN|WINDOW_CENTER)
+                       Local panel:TGadget = CreatePanel(0,0,ClientWidth(splash),ClientHeight(splash),splash,0)
+                       SetPanelColor panel,255,255,255;SetPanelPixmap panel, LoadPixmapPNG("incbin::splash.png"), PANELPIXMAP_FIT2
+                       Local progress:TGadget = CreateProgBar(2,ClientHeight(panel)-22,ClientWidth(panel)-4,20,panel)
+                       ShowGadget splash;PollSystem
+               
+               window=CreateWindow("MaxIDE",20,20,760,540,Null,WINDOW_TITLEBAR|WINDOW_RESIZABLE|WINDOW_STATUS|WINDOW_HIDDEN|WINDOW_ACCEPTFILES|WINDOW_MENU)
+               
+               ?Linux
+               SetGadgetPixmap(window, LoadPixmapPNG("incbin::window_icon.png"), GADGETPIXMAP_ICON )
+               ?
+               
+               cmdlinereq=TCmdLineRequester.Create(Self)
+               'syncmodsreq=TSyncModsRequester.Create(Self)
+               gotoreq=TGotoRequester.Create(Self)
+               findreq=TFindRequester.Create(Self)
+               replacereq=TReplaceRequester.Create(Self)
+               options=TOptionsRequester.Create(Self)
+'              progress=TProgressRequester.Create(Self)
+               projectreq=TProjectRequester.Create(Self)
+               projectprops=TProjectProperties.Create(Self)
+               searchreq=TSearchRequester.Create(Self)
+               aboutreq=TAboutRequester.Create(Self)
+               
+               UpdateProgBar progress, 0.1;PollSystem
+               
+               ReadConfig()
+
+               toolbar=CreateToolbar("incbin::toolbar.png",0,0,0,0,window )
+               
+               RemoveGadgetItem toolbar, TB_CONTINUE
+               
+               Rem
+               SetToolbarTips toolbar, ["{{tb_new}}","{{tb_open}}","{{tb_close}}","{{tb_save}}","","{{tb_cut}}","{{tb_copy}}","{{tb_paste}}","{{tb_find}}","",..
+                                        "{{tb_build}}","{{tb_buildrun}}","{{tb_step}}","{{tb_stepin}}","{{tb_stepout}}","{{tb_stop}}","","{{tb_home}}","{{tb_back}}","{{tb_forward}}"]
+               End Rem
+               
+               If Not options.showtoolbar Then HideGadget toolbar
+
+               If OutsideDesktop(winsize)
+                       winsize.set(20,20,760,540)              
+               EndIf
+               
+               UpdateProgBar progress, 0.2;PollSystem
+               
+               SetGadgetShape(window, winsize.x, winsize.y, winsize.w, winsize.h)
+
+               client=window
+               
+               split=CreateSplitter(0,0,ClientWidth(client),ClientHeight(client),client,SPLIT_VERTICAL)
+               SetGadgetLayout(split,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED)
+               
+               tabbar=CreateTabber(0,0,ClientWidth(SplitterPanel(split,SPLITPANEL_MAIN)),ClientHeight(SplitterPanel(split,SPLITPANEL_MAIN)),SplitterPanel(split,SPLITPANEL_MAIN))
+               SetGadgetLayout(tabbar,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED)
+               
+               debugtree=TDebugTree.CreateDebugTree(Self)
+
+               root=TNode.CreateNode("{{navtab_home}}")
+               
+               helproot=root.AddNode("{{navnode_help}}")
+               
+               projects=TProjects.CreateProjects(Self)         
+               root.Append projects
+       
+'              opencoderoot=root.AddNode("Open")
+               coderoot=TNode.CreateNode("{{navtab_code}}")
+               coderoot.Open()
+
+               navbar=TNavBar.Create(Self,SplitterPanel(split,SPLITPANEL_SIDEPANE))
+
+               navbar.AddView root
+               navbar.AddView coderoot
+               debugview=navbar.AddView(debugtree)
+               navbar.SelectView 0
+
+               helproot.Open
+               projects.Open
+
+               AddHandler navbar
+       
+               SetMode EDITMODE
+               
+               UpdateProgBar progress, 0.3;PollSystem
+                       
+               quickhelp=TQuickHelp.LoadCommandsTxt(bmxpath)
+
+               helppanel=THelpPanel.Create(Self)
+               
+               output=TOutputPanel.Create(Self)
+               
+               activepanel=helppanel
+               InitMenu
+               InitHotkeys
+
+               RefreshAll
+               
+               UpdateProgBar progress, 0.4;PollSystem 'allow repaint
+               
+               Local mkdocs
+               If FileType( bmxpath+"/docs/html/User Guide/index.html" )<>FILETYPE_FILE
+                       CreateDir bmxpath+"/docs/html"
+                       CreateFile bmxpath+"/docs/html/index.html"
+                       mkdocs=True
+               EndIf
+               
+               helppanel.Home()
+               
+               UpdateProgBar progress, 0.5;PollSystem
+               
+' scan projects in projlist
+               For Local pdata:TList = EachIn projlist
+                       projects.AddProject pdata
+               Next
+               
+               UpdateProgBar progress, 0.6;PollSystem
+               
+               Local tmpProgValue# = 0.6
+               Local tmpProgStep#
+               
+'open files from .ini restorelist              
+               If options.restoreopenfiles
+                       If Not openlist.IsEmpty() Then tmpProgStep = (0.3/openlist.Count())
+                       For Local f$=EachIn openlist
+                               open=OpenSource(f$)
+                               If open And f$=openlock open.SetLocked(True)
+                               tmpProgValue:+tmpProgStep;UpdateProgBar progress,tmpProgValue
+                       Next
+               EndIf
+               
+               tmpProgValue = 0.9
+               If AppArgs.length > 1 Then tmpProgStep = (0.1/(AppArgs.length-1)) Else tmpProgValue = 1.0
+               UpdateProgBar progress,tmpProgValue;PollSystem
+               
+' open files specified in command line         
+               For Local i:Int = 1 Until AppArgs.length
+                       open=OpenSource(AppArgs[i])
+                       tmpProgValue:+tmpProgStep;UpdateProgBar progress,tmpProgValue;PollSystem
+               Next
+               
+               HideGadget splash;FreeGadget splash
+               PollSystem
+               
+               SetSplitterPosition(split,splitpos);SetSplitterOrientation(split,splitorientation)
+               
+               If winmax MaximizeWindow(window)
+               ShowGadget window       
+               
+               PollSystem
+               running=True
+               
+               CreateTimer(TIMER_FREQUENCY)
+               
+               'If nomods syncmodsreq.Show     
+               
+'build docs if not there               
+               If mkdocs
+                       If Confirm( LocalizeString("{{loaderror_docsnotfound}}") ) And CloseAll( False ) DocMods
+               EndIf
+               
+       End Method
+       
+       Method DocMods()
+               Local cmd$=quote(bmxpath+"/bin/makedocs")
+               execute cmd,LocalizeString("{{output_msg_rebuildingdocs}}"),MENUTRIGGERSYNCDOCS
+       ?MacOS
+               RanLibMods()
+       ?
+       End Method
+               
+       Method SyncDocs()
+               helppanel.SyncDocs()
+               quickhelp=TQuickHelp.LoadCommandsTxt(bmxpath)
+               helppanel.Home
+       End Method
+
+       Method InitMenu()
+               Local menu:TGadget,file:TGadget,edit:TGadget,program:TGadget,tools:TGadget
+               Local help:TGadget,buildoptions:TGadget
+               Local buildmods:TGadget,buildallmods:TGadget,syncmods:TGadget,docmods:TGadget
+
+               Local MENUMOD=MODIFIER_COMMAND
+
+               If options.systemkeys
+                       MENUMOD=MODIFIER_CONTROL
+               EndIf
+
+               menu=WindowMenu(window)
+
+               file=CreateMenu("{{menu_file}}",0,menu)
+               CreateMenu "{{menu_file_new}}",MENUNEW,file,KEY_N,MENUMOD
+               CreateMenu "{{menu_file_open}}",MENUOPEN,file,KEY_O,MENUMOD
+               recentmenu=CreateMenu("{{menu_file_open_recent}}",0,file)
+               CreateMenu "",0,file
+               CreateMenu "{{menu_file_closetab}}",MENUCLOSE,file,KEY_W,MENUMOD
+               CreateMenu "{{menu_file_closealltabs}}",MENUCLOSEALL,file,KEY_W,MENUMOD|MODIFIER_SHIFT
+               CreateMenu "{{menu_file_closeothertabs}}",MENUCLOSEOTHERS,file,KEY_W,MENUMOD|MODIFIER_ALT
+               CreateMenu "",0,file
+               CreateMenu "{{menu_file_save}}",MENUSAVE,file,KEY_S,MENUMOD
+               CreateMenu "{{menu_file_saveas}}",MENUSAVEAS,file,KEY_S,MENUMOD|MODIFIER_SHIFT
+               CreateMenu "{{menu_file_saveall}}",MENUSAVEALL,file
+               CreateMenu "",0,file
+
+               If options.systemkeys
+?MacOS
+                       CreateMenu "{{menu_file_nexttab}}",MENUNEXT,file,KEY_RIGHT,MENUMOD
+                       CreateMenu "{{menu_file_prevtab}}",MENUPREV,file,KEY_LEFT,MENUMOD
+?Not MacOS
+                       CreateMenu "{{menu_file_nexttab}}",MENUNEXT,file,KEY_RIGHT,MODIFIER_ALT
+                       CreateMenu "{{menu_file_prevtab}}",MENUPREV,file,KEY_LEFT,MODIFIER_ALT
+?
+               Else
+                       CreateMenu "{{menu_file_nexttab}}",MENUNEXT,file,KEY_RIGHT,MENUMOD
+                       CreateMenu "{{menu_file_prevtab}}",MENUPREV,file,KEY_LEFT,MENUMOD               
+               EndIf
+               CreateMenu "",0,file
+               CreateMenu "{{menu_file_importbb}}",MENUIMPORTBB,file
+               CreateMenu "",0,file
+               CreateMenu "{{menu_file_ideoptions}}",MENUOPTIONS,file
+               CreateMenu "{{menu_file_projectmanager}}",MENUPROJECTMANAGER,file       
+               CreateMenu "",0,file
+               CreateMenu "{{menu_file_print}}",MENUPRINT,file,KEY_P,MENUMOD
+?Not MacOS
+               CreateMenu "",0,file
+               CreateMenu "{{menu_file_exit}}",MENUQUIT,file
+?
+               edit=CreateMenu("{{menu_edit}}",0,menu)
+               CreateMenu "{{menu_edit_undo}}",MENUUNDO,edit,KEY_Z,MENUMOD
+?MacOS
+               CreateMenu "{{menu_edit_redo}}",MENUREDO,edit,KEY_Z,MENUMOD|MODIFIER_SHIFT
+?Not MacOS
+               CreateMenu "{{menu_edit_redo}}",MENUREDO,edit,KEY_Y,MENUMOD
+?
+               CreateMenu "",0,edit
+               CreateMenu "{{menu_edit_cut}}",MENUCUT,edit,KEY_X,MENUMOD
+               CreateMenu "{{menu_edit_copy}}",MENUCOPY,edit,KEY_C,MENUMOD
+               CreateMenu "{{menu_edit_paste}}",MENUPASTE,edit,KEY_V,MENUMOD
+               CreateMenu "",0,edit
+               CreateMenu "{{menu_edit_selectall}}",MENUSELECTALL,edit,KEY_A,MENUMOD
+               CreateMenu "",0,edit
+               CreateMenu "{{menu_edit_blockindent}}",MENUINDENT,edit,KEY_CLOSEBRACKET,MENUMOD
+               CreateMenu "{{menu_edit_blockoutdent}}",MENUOUTDENT,edit,KEY_OPENBRACKET,MENUMOD
+               CreateMenu "",0,edit
+               CreateMenu "{{menu_edit_find}}",MENUFIND,edit,KEY_F,MENUMOD
+?MacOS
+               CreateMenu "{{menu_edit_findnext}}",MENUFINDNEXT,edit,KEY_G,MENUMOD
+               CreateMenu "{{menu_edit_replace}}",MENUREPLACE,edit,KEY_H,MENUMOD
+               CreateMenu "{{menu_edit_gotoline}}",MENUGOTO,edit,KEY_L,MENUMOD
+?Not MacOS
+               CreateMenu "{{menu_edit_findnext}}",MENUFINDNEXT,edit,KEY_F3
+               CreateMenu "{{menu_edit_replace}}",MENUREPLACE,edit,KEY_H,MENUMOD
+               CreateMenu "{{menu_edit_gotoline}}",MENUGOTO,edit,KEY_G,MENUMOD
+?
+               CreateMenu "",0,edit
+               CreateMenu "{{menu_edit_findinfiles}}",MENUFINDINFILES,edit,KEY_F,MENUMOD|MODIFIER_SHIFT
+               
+               program=CreateMenu("{{menu_program}}",0,menu)
+               CreateMenu "{{menu_program_build}}",MENUBUILD,program,KEY_B,MENUMOD
+               CreateMenu "{{menu_program_buildandrun}}",MENURUN,program,KEY_R,MENUMOD
+               CreateMenu "{{menu_program_commandline}}",MENUCOMMANDLINE,program
+               CreateMenu "",0,program
+               CreateMenu "{{menu_program_step}}",MENUSTEP,program,KEY_F9
+               CreateMenu "{{menu_program_stepin}}",MENUSTEPIN,program,KEY_F10
+               CreateMenu "{{menu_program_stepout}}",MENUSTEPOUT,program,KEY_F11
+               CreateMenu "{{menu_program_terminate}}",MENUSTOP,program
+               buildoptions=CreateMenu("{{menu_program_buildoptions}}",0,program)
+               quickenable=CreateMenu("{{menu_program_buildoptions_quick}}",MENUQUICKENABLED,buildoptions)
+               debugenable=CreateMenu("{{menu_program_buildoptions_debug}}",MENUDEBUGENABLED,buildoptions)
+               If (FileType( BlitzMaxPath()+"/mod/brl.mod/blitz.mod/blitz_gc_ms.c" )=FILETYPE_FILE) ..
+                       Or (FileType( BlitzMaxpath()+"/mod/brl.mod/blitz.mod/bdwgc" )=FILETYPE_DIR)
+                               threadedenable=CreateMenu("{{menu_program_buildoptions_threaded}}",MENUTHREADEDENABLED,buildoptions)
+               EndIf
+               guienable=CreateMenu("{{menu_program_buildoptions_guiapp}}",MENUGUIENABLED,buildoptions)
+               CreateMenu "",0,program
+               CreateMenu "{{menu_program_lockbuildfile}}",MENULOCKBUILD,program
+               CreateMenu "{{menu_program_unlockbuildfile}}",MENUUNLOCKBUILD,program
+               CreateMenu "",0,program
+               'syncmods=CreateMenu("{{menu_program_syncmods}}",MENUSYNCMODS,program)
+               'CreateMenu "",0,program
+               buildmods=CreateMenu("{{menu_program_buildmods}}",MENUBUILDMODULES,program,KEY_D,MENUMOD)
+               buildallmods=CreateMenu("{{menu_program_rebuildallmods}}",MENUBUILDALLMODULES,program)
+               docmods=CreateMenu("{{menu_program_rebuilddocs}}",MENUDOCMODS,program)
+               
+               help=CreateMenu("{{menu_help}}",0,menu)
+               CreateMenu "{{menu_help_home}}",MENUHOME,help
+               CreateMenu "{{menu_help_back}}",MENUBACK,help
+               CreateMenu "{{menu_help_forward}}",MENUFORWARD,help
+               CreateMenu "{{menu_help_quickhelp}}",MENUQUICKHELP,help,KEY_F1
+               CreateMenu "{{menu_help_aboutmaxide}}",MENUABOUT,help
+               
+               If quickenabled CheckMenu quickenable
+               If debugenabled CheckMenu debugenable
+               If threadedenabled CheckMenu threadedenable
+               If guienabled CheckMenu guienable
+               
+?Win32         
+               Local mingw$=getenv_("MINGW")
+               If Not mingw
+                       DisableMenu buildmods
+                       DisableMenu buildallmods
+               EndIf
+?              
+'              If is_demo
+'                      DisableMenu syncmods
+'              EndIf
+               
+               RefreshRecentFiles
+               UpdateWindowMenu window
+       End Method
+
+       Method RunCode()
+               If mode=DEBUGMODE And debugtree.cancontinue
+                       output.Go()
+                       Return
+               EndIf
+               output.Stop()
+               SaveAll()
+               If lockedpanel
+                       lockedpanel.invoke TOOLRUN
+               Else
+                       activepanel.invoke TOOLRUN
+               EndIf
+       End Method
+       
+       Method BuildCode()
+               output.Stop()
+               SaveAll()
+               If lockedpanel
+                       lockedpanel.invoke TOOLBUILD
+               Else
+                       activepanel.invoke TOOLBUILD
+               EndIf
+       End Method
+               
+               
+       Method AddEventHotKey(key,mods,id,data)
+               SetHotKeyEvent key,mods,CreateEvent(id,Null,data)
+       End Method
+               
+       Method InitHotkeys()
+               AddEventHotKey KEY_F5,MODIFIER_NONE,EVENT_MENUACTION,MENURUN
+               AddEventHotKey KEY_F7,MODIFIER_NONE,EVENT_MENUACTION,MENUBUILD
+       End Method
+               
+       Method SaveAll()
+               For Local panel:TToolPanel = EachIn panels
+                       panel.invoke TOOLQUICKSAVE                                              
+               Next
+       End Method
+       
+       Method Restart()
+               If Confirm(LocalizeString("{{request_restart}}"))
+                       Quit
+               EndIf
+       End Method
+       
+       Method RefreshAll()     
+' hide/show toolbar
+               If options.showtoolbar Then ShowGadget toolbar Else HideGadget toolbar
+' refresh panels
+               For Local panel:TToolPanel = EachIn panels
+                       panel.invoke TOOLREFRESH                                                
+               Next
+' refresh navbar
+               navbar.invoke TOOLREFRESH
+       End Method
+
+       Method SnapshotWindow()
+               If WindowMaximized(window)
+                       winmax=True
+               Else
+                       If Not WindowMinimized(window)
+                               winmax=False
+                               winsize.x=GadgetX(window)
+                               winsize.y=GadgetY(window)
+                               winsize.w=GadgetWidth(window)
+                               winsize.h=GadgetHeight(window)
+                       EndIf
+               EndIf
+               options.showtoolbar = Not GadgetHidden(toolbar)
+       End Method
+       
+       Method OnMenu(menu,extra:Object=Null)
+               Local   index
+               
+               Local   tool:TTool = TTool(extra)
+               If tool
+                       tool.invoke(TOOLMENU,""+menu)
+                       Return
+               EndIf
+       
+               Select menu
+                       Case MENUNEW
+                               OpenSource ""
+                       Case MENUOPEN
+                               OpenSource "."
+                       Case MENUCLOSE
+                               currentpanel.invoke TOOLCLOSE
+                       Case MENUCLOSEALL
+                               CloseAll True
+                       Case MENUCLOSEOTHERS
+                               CloseAll True, False
+                       Case MENUSAVE
+                               currentpanel.invoke TOOLSAVE                                            
+                       Case MENUSAVEAS                 
+                               currentpanel.invoke TOOLSAVEAS                                          
+                       Case MENUSAVEALL
+                               SaveAll()
+                       Case MENUPRINT
+                               currentpanel.invoke TOOLPRINT                                           
+                       Case MENUQUIT
+                               Quit()
+
+                       Case MENUGOTO
+                               gotoreq.Show()
+                       Case MENUFIND
+                               currentpanel.invoke TOOLFIND
+                       Case MENUFINDNEXT
+                               currentpanel.invoke TOOLFINDNEXT
+                       Case MENUREPLACE
+                               replacereq.Show()
+
+                       Case MENUUNDO currentpanel.invoke TOOLUNDO
+                       Case MENUREDO currentpanel.invoke TOOLREDO
+
+                       Case MENUCUT currentpanel.invoke TOOLCUT
+                       Case MENUCOPY currentpanel.invoke TOOLCOPY
+                       Case MENUPASTE currentpanel.invoke TOOLPASTE
+                       Case MENUSELECTALL currentpanel.invoke TOOLSELECTALL
+                                                                               
+                       Case MENUBUILD
+                               BuildCode()
+                       Case MENURUN
+                               RunCode()
+
+                       Case MENUBUILDMODULES
+                               If CheckDemo() BuildModules False
+                       Case MENUBUILDALLMODULES
+                               If CheckDemo() BuildModules True        
+                       'Case MENUSYNCMODS
+                       '       If CheckDemo() And CloseAll(False) syncmodsreq.Show
+                       Case MENUDOCMODS
+                               If CheckDemo() And CloseAll(False) DocMods
+                       Case MENUTRIGGERDOCMODS
+                               DocMods()
+                       Case MENUTRIGGERSYNCDOCS
+                               SyncDocs()
+                               
+                       Case MENUSTEP If output output.StepOver()
+                       Case MENUSTEPIN If output output.StepIn()
+                       Case MENUSTEPOUT If output output.StepOut()
+                       Case MENUSTOP If output output.Stop()
+
+                       Case MENULOCKBUILD
+                               activepanel.invoke TOOLLOCK
+                       Case MENUUNLOCKBUILD
+                               If lockedpanel lockedpanel.invoke TOOLUNLOCK
+                       
+                       Case MENUCOMMANDLINE cmdlinereq.Show
+                       
+                       Case MENUQUICKENABLED
+                               If quickenabled
+                                       quickenabled=False
+                                       UncheckMenu quickenable                                                 
+                               Else
+                                       quickenabled=True
+                                       CheckMenu quickenable
+                               EndIf
+                               UpdateWindowMenu window
+
+                       Case MENUDEBUGENABLED
+                               If debugenabled
+                                       debugenabled=False
+                                       UncheckMenu debugenable                                                 
+                               Else
+                                       debugenabled=True
+                                       CheckMenu debugenable
+                               EndIf
+                               UpdateWindowMenu window
+                               
+                       Case MENUTHREADEDENABLED
+                               If threadedenabled
+                                       threadedenabled=False
+                                       UncheckMenu threadedenable                                                      
+                               Else
+                                       threadedenabled=True
+                                       CheckMenu threadedenable
+                               EndIf
+                               UpdateWindowMenu window
+                               
+                       Case MENUGUIENABLED
+                               If guienabled
+                                       guienabled=False
+                                       UncheckMenu guienable                                                   
+                               Else
+                                       guienabled=True
+                                       CheckMenu guienable
+                               EndIf
+                               UpdateWindowMenu window
+
+                       Case MENUIMPORTBB
+                               ImportBB
+                               
+                       Case MENUFINDINFILES
+                               If activepanel Then searchreq.ShowWithPath( ExtractDir(activepanel.path) ) Else searchreq.Show()
+                               
+                       Case MENUPROJECTMANAGER
+                               projectreq.Open projects
+                       Case MENUSHOWCONSOLE
+                               If output Then output.Open()
+
+                       Case MENUOPTIONS
+                               options.Show()
+                               
+                       Case MENUNEXT
+                               If Not currentpanel Return
+                               index=currentpanel.index+1
+                               If index=panels.length index=0
+                               SelectPanel panels[index]
+
+                       Case MENUPREV
+                               If Not currentpanel Return
+                               index=currentpanel.index-1
+                               If index<0 index=panels.length-1
+                               SelectPanel panels[index]
+                       
+                       Case MENUQUICKHELP
+                               currentpanel.invoke TOOLHELP
+                       
+                       Case MENUHOME
+                               helppanel.Home()
+                               SelectPanel helppanel
+                       Case MENUBACK
+                               helppanel.Back()
+                               SelectPanel helppanel
+                       Case MENUFORWARD
+                               helppanel.Forward()
+                               SelectPanel helppanel
+                       Case MENUABOUT
+                               aboutreq.Show()
+                               'Notify (ABOUT.Replace( "{bcc_version}",BCC_VERSION ))
+                       Case MENUINDENT
+                               currentpanel.invoke TOOLINDENT
+                       Case MENUOUTDENT
+                               currentpanel.invoke TOOLOUTDENT
+                               
+                       Case MENUNEWVIEW
+                               navbar.invoke TOOLNEWVIEW
+                               
+               End Select
+               
+               If menu>=MENURECENT
+                       Local f:String = String(recentfiles.ValueAtIndex(menu-MENURECENT))
+                       If f$ OpenSource f$
+               EndIf
+       End Method
+       
+       Method poll()
+               
+               Local   src:TGadget
+               Local event = WaitEvent()
+               
+               If Not activerequesters.IsEmpty()
+                       Select event
+                               Case EVENT_MENUACTION
+                                       src = ActiveGadget()
+                                       If src And (GadgetClass(src) = GADGET_TEXTFIELD) Then
+                                               Select EventData()
+                                                       Case MENUSELECTALL
+                                                               ActivateGadget(src)
+                                                       Case MENUCOPY
+                                                               GadgetCopy(src)
+                                                       Case MENUPASTE
+                                                               GadgetPaste(src)
+                                                       Case MENUCUT
+                                                               GadgetCut(src)
+                                               EndSelect
+                                               Return
+                                       EndIf
+                                       src = Null
+                               Case EVENT_MOUSEENTER,EVENT_MOUSELEAVE,EVENT_GADGETLOSTFOCUS
+                                       Return
+                       End Select
+                       'DebugLog CurrentEvent.ToString()
+                       For Local activerequester:TRequester = EachIn activerequesters
+                               If activerequester.Poll() Then Return
+                       Next
+               EndIf
+
+               For Local handler:TEventHandler = EachIn eventhandlers
+                       handler.OnEvent()
+               Next
+               
+               src = TGadget(EventSource())
+
+               Select event
+                       Case EVENT_GADGETACTION
+                               Select EventSource()
+                                       Case toolbar
+                                               Select EventData()
+                                                       Case TB_NEW OpenSource ""
+                                                       Case TB_OPEN OpenSource "."
+                                                       Case TB_CLOSE currentpanel.invoke TOOLCLOSE
+                                                       Case TB_SAVE currentpanel.invoke TOOLSAVE       
+                                                       Case TB_CUT currentpanel.invoke TOOLCUT
+                                                       Case TB_COPY currentpanel.invoke TOOLCOPY
+                                                       Case TB_PASTE currentpanel.invoke TOOLPASTE
+                                                       Case TB_FIND currentpanel.invoke TOOLFIND
+                                                       Case TB_BUILD BuildCode
+                                                       Case TB_BUILDRUN RunCode
+                                                       Case TB_STEP If output output.stepover
+                                                       Case TB_STEPIN If output output.stepin
+                                                       Case TB_STEPOUT If output output.stepout
+                                                       Case TB_STOP If output output.Stop
+                                                       Case TB_HOME helppanel.Home;SelectPanel helppanel
+                                                       Case TB_BACK helppanel.Back;SelectPanel helppanel
+                                                       Case TB_FORWARDS helppanel.Forward;SelectPanel helppanel
+                                               End Select
+                                               
+                                       Case tabbar
+                                               Local index = EventData()
+                                               If index>=0 And index<panels.length
+                                                       SelectPanel panels[index]
+                                               EndIf
+                               End Select
+                               
+                       Case EVENT_WINDOWACCEPT, EVENT_APPOPENFILE
+                               OpenSource EventText()
+                               
+                       Case EVENT_APPTERMINATE
+                               Quit()
+                               
+                       Case EVENT_WINDOWACTIVATE
+                               If (src=window) Then SelectPanel currentpanel
+                               
+                       Case EVENT_WINDOWCLOSE
+                               If (src=window) Then Quit()
+                               
+                       Case EVENT_WINDOWMOVE, EVENT_WINDOWSIZE
+                               If (src=window) Then SnapshotWindow()
+                               
+                       Case EVENT_MENUACTION
+                               OnMenu EventData(),EventExtra()
+
+               EndSelect
+       EndMethod
+
+EndType
+
+Function CacheAndLoadText$(url:Object)
+       Local tmpResult$
+       Local tmpBytes:Byte[] = LoadByteArray(url)
+       url = CreateRamStream( tmpBytes, tmpBytes.length, True, False )
+       tmpResult = LoadText(url)
+       TRamStream(url).Close()
+       Return tmpResult
+EndFunction
diff --git a/src/maxide/readme.txt b/src/maxide/readme.txt
new file mode 100644 (file)
index 0000000..6ac15f7
--- /dev/null
@@ -0,0 +1,6 @@
+
+version 1.43
+
+FLTK smooth font
+fixed crash sending utf8 to fltk output - disabled utf8 processing in TOutputPanel write
+
diff --git a/src/maxide/splash.png b/src/maxide/splash.png
new file mode 100644 (file)
index 0000000..2005420
Binary files /dev/null and b/src/maxide/splash.png differ
diff --git a/src/maxide/toolbar.png b/src/maxide/toolbar.png
new file mode 100644 (file)
index 0000000..a4d4110
Binary files /dev/null and b/src/maxide/toolbar.png differ
diff --git a/src/maxide/window_icon.png b/src/maxide/window_icon.png
new file mode 100644 (file)
index 0000000..9313bcc
Binary files /dev/null and b/src/maxide/window_icon.png differ