Updated it, no need to change the bmxfolder variable to your installation (and added url to mod title so that the mod can be opened in the IDE):
' ' Documenta.bmx ' BlitzMax Module Documentation Generator ' ' Version: 0.77 (with modifications from Perturbatio) ' Purpose: To create nice help files for BlitzMax. ' Author: Mikkel Fredborg ' ' Warning: Use this at your own risk! It will overwrite your original BlitzMax ' Command Reference. Please make sure to back up the documents before ' running Documenta! ' ' ToDo: Add better (less hardcoded) css formatting (and make it prettier). ' Add the ability to import additional comments files. ' Comment code :) ' ' History: ' 0.77 - automatically retrieve bmax folder so that it will run without need to configure ' 0.76 - Added url to module source so that the IDE can open it (PERTURBATIO) ' 0.75 - Relative file paths ' 0.71 - Compatible with BlitzMax 1.03 ' 0.7 - Converts language reference and user guide! ' 0.65 - Minor tweaks ' 0.6 - Navbar works with Firefox ' Overwrites original Blitzmax module documentation!!! ' 0.5 - Auto fixes table layout/style ' Fix Intro formatting ' 0.4 - Recognizes Global function definitions (ie. Global AppArgs$[]="bbAppArgs") ' 0.3 - Skip Private and Extern sections ' Exclude modules which doesn't have any functions ' 0.2 - Examples and Module introductions are included ' 0.1 - Basic stuff ' ' ' Change this to your BlitzMax folder Global bmaxfolder:String = getenv_("BMXPATH") ' ' Modify these if you want extra stuff Const SKIP_PRIVATE = True ' Skips commands private to a module Const SKIP_EXTERN = False ' Skip extern commands Const SKIP_NONDOCED = False ' Skip non documented commands ' ' Fix up path if it isn't slashed bmaxfolder = StripSlash(bmaxfolder)+"/" bmaxfolder = bmaxfolder.Replace("","/") If FileType(StripSlash(bmaxfolder)) = 0 Notify "Incorrect BlitzMax folder!~n~q"+bmaxfolder+"~q!" End EndIf ' ' Destination folder...only works correctly if it's the bmax folder :) Global destfolder:String = bmaxfolder ' ' Warn if overwriting If bmaxfolder = destfolder If Proceed("Warning!~n~nThis will overwrite some of the original BlitzMax help files.~nPlease make sure you have a backup of your 'BlitzMax/doc/bmxmods' folder!~n~nDo you wish to continue?",True)<>1 Print "User aborted...What a sissy :)" End EndIf EndIf ' ' Do NOT modify Const linefeed:String = "~r~n" Const htmlext:String = ".html" Const backuppre:String = "documenta_backup_" Global modlist:TList = New TList Global funlist:TList = New TList Global CSS_List:TList = New TList Type dmod Field docfile:String Field file:String Field name:String Field info:String Field intro:String Field funclist:TList = New TList Method New() modlist.addlast Self End Method Method AddFunction:dfunc() Local f:dfunc = New dfunc f.mymod = Self Self.funclist.addlast f funlist.addlast f Return f End Method Method compare:Int(otherObj:Object) Local m:dmod = dmod(otherObj) If Not m Then Return 1 Return Self.name.compare(m.name) End Method End Type Type dfunc Field name:String Field sname:String Field param:String Field desc:String Field rets:String Field about:String Field example:String Field exfile:String Field mymod:dmod Field keyword:Int Method compare:Int(otherObj:Object) Local f:dfunc = dfunc(otherObj) If Not f Then Return 1 Return Self.sname.compare(f.sname) End Method End Type ' ' Converted from: ' <a href="http://www.codeguru.com/Cpp/misc/misc/fileanddirectorynaming/article.php/c263/" target="_blank">www.codeguru.com/Cpp/misc/misc/fileanddirectorynaming/article.php/c263/</a> ' Function GetRelativeFilename:String(currentDirectory:String, absoluteFilename:String) Local slash = Asc("/") currentDirectory = currentDirectory.Replace("","/") absoluteFilename = absoluteFilename.Replace("","/") If currentDirectory[currentDirectory.length-1]<>slash currentDirectory:+"/" EndIf Local afMarker:Int = 0 Local rfMarker:Int = 0 Local cdLen:Int = 0 Local afLen:Int = 0 Local i:Int = 0 Local levels:Int = 0 Local relativeFilename:String cdLen = currentDirectory.length afLen = absoluteFilename.length ' Handle DOS names that are on different drives: If (Lower(Chr(currentDirectory[0])) <> Lower(Chr(absoluteFilename[0]))) ' Not on the same drive, so only absolute filename will do relativeFilename = absoluteFilename Return relativeFilename EndIf ' they are on the same drive, find out how much of the current directory ' is in the absolute filename i = 3 While((i < afLen) And (i < cdLen) And (Lower(Chr(currentDirectory[i])) = Lower(Chr(absoluteFilename[i])))) i:+1 Wend If (i = cdLen And (absoluteFilename[i] = slash Or absoluteFilename[i-1] = slash)) ' the whole current directory name is in the file name, ' so we just trim off the current directory name to get the ' current file name. If(absoluteFilename[i] = slash) ' a directory name might have a trailing slash but a relative ' file name should not have a leading one... i:+1 EndIf relativeFilename = absoluteFilename[i..afLen] Return relativeFilename EndIf ' The file is not in a child directory of the current directory, so we ' need to step back the appropriate number of parent directories by ' using ".."s. First find out how many levels deeper we are than the ' common directory afMarker = i; levels = 1; ' count the number of directory levels we have to go up to get to the ' common directory While(i < cdLen) i:+1 If(currentDirectory[i] = slash) ' make sure it's not a trailing slash i:+1 If i<cdLen'(currentDirectory[i] != '\0') levels:+1 EndIf EndIf Wend ' move the absolute filename marker back to the start of the directory name ' that it has stopped in. While(afMarker > 0 And absoluteFilename[afMarker-1] <> slash) afMarker:-1 Wend ' add the appropriate number of "../"s. rfMarker = 0; For i = 0 Until levels relativeFilename:+"../" Next ' copy the rest of the filename into the result string relativeFilename:+absoluteFilename[afMarker..afLen] Return relativeFilename End Function ' ' Scans the BlitzMax module folder to find all modules Function ScanModFolder(f:String) f = StripSlash(f) Local files:String[] files = LoadDir(f,True) ' ' Find module files For Local fi:String = EachIn files If KeyDown(KEY_ESCAPE) Then Exit Local file:String = f+"/"+fi If FileType(file)=1 If Lower(fi[fi.length-4..fi.length])=".bmx" ScanBMXFile(file) EndIf Else ScanModFolder(file) EndIf FlushMem Next End Function ' ' Scans a .bmx file and extracts info from modules Function ScanBMXFile(file:String) Local m:dmod Local bbdoc:String Local returns:String Local about:String Local scanmode:Int = 0 Local keyword:Int = False Local inextern:Int = False Local inprivate:Int = False Local temp:String Local temp2:String Local f1:Int Local f2:Int Local stream = ReadFile(file) If stream While Not Eof(stream) l:String = ReadLine(stream) If SKIP_EXTERN If Lower(l[0..6]) = "extern" inextern = True EndIf If Lower(l[0..9]) = "endextern" Or Lower(l[0..10]) = "end extern" inextern = False EndIf EndIf If SKIP_PRIVATE If Lower(l[0..7]) = "private" inprivate = True EndIf If Lower(l[0..6]) = "public" inprivate = False EndIf EndIf If inextern = False And inprivate = False If m = Null ' ' module name If Lower(l[0..7]) = "module " m = New dmod m.file = file m.name = FormatString(l[7..l.length]) m.info = "<tr><td class=~qmodinfoleft~q>Module</td><td class=~qmodinforight~q>"+m.name+"</td></tr>"+linefeed EndIf Else ' ' Module info If Lower(l[0..10]) = "moduleinfo" f1 = l.find("~q",0)+1 f2 = l.find("~q",f1) If f1>0 And f2>0 temp = l[f1..f2] f1 = temp.find(":",0) If f1 temp2 = FormatString(temp[0..f1]) temp = FormatString(temp[f1+1..temp.length]) EndIf m.info = m.info+"<tr><td class=~qmodinfoleft~q>"+temp2+"</td><td class=~qmodinforight~q>"+temp+"</td></tr>"+linefeed EndIf EndIf Local ol = l.length If Lower(l[0..6])="bbdoc:" l = l[6..l.length] scanmode = 1 EndIf If Lower(l[0..8])="returns:" l = l[8..l.length] scanmode = 2 EndIf If Lower(l[0..6])="about:" l = l[6..l.length] scanmode = 3 EndIf If scanmode If Lower(l[0..6])="endrem" Or Lower(l[0..7])="end rem" Or ol < 2 scanmode = False Else If scanmode = 1 bbdoc = bbdoc+FormatString(l,True)+" " If scanmode = 2 returns = returns+FormatString(l,True)+" " If scanmode = 3 about = about+FormatString(l,True)+" " EndIf EndIf If keyword If f:dfunc f.desc = bbdoc f.rets = returns f.about = about EndIf EndIf If Lower(l[0..7])="global " If bbdoc = "" l = ".."+l EndIf EndIf If Lower(l[0..9])="function " Or Lower(l[0..9])="keyword: " Or Lower(l[0..7])="global " f:dfunc = m.addfunction() If Lower(l[0..9])="function " f.desc = bbdoc f.rets = returns f.about = about keyword = False f1 = l.find("(") f.name = l[9..f1] f1 = f1+1 f2 = l.length Local level = 1 For Local i = f1 Until l.length If l[i] = Asc("(") Then level:+1 If l[i] = Asc(")") Then level:-1 If level = 0 f2 = i Exit EndIf Next f.param = l[f1..f2] ElseIf Lower(l[0..9])="keyword: " keyword = True f.name = l[9..l.length] f.name = f.name.Replace("~q","") f.name = f.name.Trim() f.keyword = True Else keyword = False f.name = l[7..l.find("=")]+"()" f.name = f.name.Trim() f.keyword = True f.desc = bbdoc f.rets = returns f.about = about keyword = False EndIf bbdoc = "" returns = "" about = "" f.sname = f.name For i = 0 Until f.sname.length If f.sname[i] = Asc("$") Or f.sname[i] = Asc("#") Or f.sname[i] = Asc("%") Or f.sname[i] = Asc(":") Or f.sname[i] = Asc("!") f.sname = f.sname[0..i] Exit EndIf Next EndIf EndIf EndIf Wend CloseFile(stream) EndIf If m <> Null Print file EndIf Return m<>Null End Function ' ' Formats a string with links, styles etc. Function FormatString:String(s:String,aboutmode:Int=False) Local f1:Int,f2:Int,i:Int Local link:String ' ' Remove non printable characters before and after s = s.Trim() ' ' Remove starting break If Lower(s[0..4]) = "<br>" s = s[4..s.length] s = s.Trim() EndIf ' ' We don't like <p> s = s.Replace("<p>","<br><br>") s = s.Replace("</p>","<br><br>") ' ' Fix tables s = s.Replace("<table>","<table class=~qsubtable~q>") s = s.Replace("<th>","<th class=~qsubth~q>") s = s.Replace("<td>","<td class=~qsubtd~q>") ' ' Auto fix http:// links f1 = s.find("http://") f2 = s.length If f1=>0 For i = f1 Until s.length If s[i]<=32 f2 = i Exit EndIf Next link:String = s[f1..f2] s = s[0..f1]+"<a href=~q"+link+"~q target=~q_blank~q>"+link+"</a>"+s[f2..s.length] EndIf If aboutmode ' ' bbdoc #something = link to another function Repeat f1 = s.find("#") f2 = s.length If f1=>0 For i = f1 Until s.length If s[i]<=32 Or s[i]=Asc(",") Or s[i]=Asc(".") Or s[i]=Asc(")") Or s[i]=Asc("(") f2 = i Exit EndIf Next link:String = s[f1+1..f2] s = s[0..f1]+"<a href=~q***"+link+"~q>"+link+"</a>"+s[f2..s.length] EndIf Until f1<0 ' ' bbdoc @something = Parameter description Repeat f1 = s.find("@") f2 = s.length If f1=>0 For i = f1 Until s.length If s[i]<=32 Or s[i]=Asc(",") Or s[i]=Asc(".") Or s[i]=Asc(")") Or s[i]=Asc("(") f2 = i Exit EndIf Next link:String = s[f1+1..f2] s = s[0..f1]+"<font class=~qfuncparam~q>"+link+"</font>"+s[f2..s.length] EndIf Until f1<0 EndIf Return s End Function ' ' Fixes up HTML files to look nicer Function ReformatHTML:String(s:String,isIntro:Int=False) ' Remove header s = RemoveSection(s,"<head>","</head>") ' ' Fix tables s = ReplaceSection(s,"<table",">","<table class=~qsubtable~q>") s = ReplaceSection(s,"<th",">","<th class=~qsubth~q>") s = ReplaceSection(s,"<td",">","<td class=~qsubtd~q>") If isIntro ' Remove original title s = RemoveSection(s,"<h1>","</h1>") ' ' Add some stuff :) s = "<h2>Introduction</h2>"+s Else ' ' Fix title s = s.Replace("<h1>","<tr><td class=~qmodulename~q>") s = s.Replace("</h1>","</td></tr><tr><td class=~qmoduleintro~q>") EndIf ' Remove html and body tags s = s.Replace("<html>","") s = s.Replace("</html>","") s = s.Replace("<body>","") s = s.Replace("</body>","") s = s.Trim() ' ' We don't like <p> s = s.Replace("<p>","<br><br>") s = s.Replace("</p>","<br><br>") ' ' Replace styling s = s.Replace("class=syntax","class=~qfuncparam~q") s = s.Replace("class=token","class=~qfuncname~q") ' ' Fix headings s = s.Replace("<h2>","</td></tr><tr><td class=~qmoduleintrohead~q>") s = s.Replace("</h2>","</td></tr><tr><td class=~qmoduleintro~q>") Return s End Function ' ' Fixes up navbar.html to look nicer Function ReformatNavbar:String(s:String) ' Remove header s = RemoveSection(s,"<head>","</head>") ' Remove html and body tags s = s.Replace("<html>","") s = s.Replace("</html>","") s = s.Replace("<body>","") s = s.Replace("</body>","") s = s.Trim() ' Replace <bold> tag s = s.Replace("<b>","<div class=~qnav~q>") s = s.Replace("</b>","</div>") ' Remove <br> tags s = s.Replace("<br>","") ' fix styles s = s.Replace("class=null","class=~qnavmodlink~q") s = s.Replace("<a","<div class=~qnavmod~q><a") s = s.Replace("</a>","</a></div>") Return s End Function ' ' Removes a section of string 's' between 'a' and 'b'. ' If 'all' is true 'a' and 'b' is removed as well. Function RemoveSection:String(s:String,a:String,b:String,all:Int=True) Local f1 = s.find(a) If f1=>0 Local f2 = s.find(b,f1) If f2=>0 If all s = s[0..f1]+s[f2+b.length..s.length] Else s = s[0..f1+a.length]+s[f2..s.length] EndIf EndIf EndIf Return s End Function Function ReplaceSection:String(s:String,a:String,b:String,repl:String) Local f1 = 0 While f1=>0 f1 = s.find(a,f1) If f1=>0 Local f2 = s.find(b,f1) If f2=>0 s = s[0..f1]+repl+s[f2+b.length..s.length] EndIf f1:+1 EndIf Wend Return s End Function ' ' Fixes html links to functions/commands Function FixFunctionRefs:String(s:String,m:dmod) Local f1 = 0 While f1=>0 f1 = s.find("***",f1) If f1=>0 Local f2 = s.find("~q",f1+3) If f2=>0 Local funname:String = s[f1+3..f2] Local found = False ' ' Check the same mod first For ff:dfunc = EachIn m.funclist If Lower(ff.sname) = Lower(funname) s = s[0..f1]+"#"+ff.sname+s[f2..s.length] found = True EndIf Next If found = False ' ' Check other mods, if the reference is not within the same mod For ff:dfunc = EachIn funlist If Lower(ff.sname) = Lower(funname) relFile:String = GetRelativeFilename(ExtractDir(m.docfile),ff.mymod.docfile) s = s[0..f1]+relFile+"#"+ff.sname+s[f2..s.length] EndIf Next EndIf EndIf f1 = f1+1 EndIf Wend Return s End Function ' ' Finds Example source files for commands, and intro.html files ' if they exist for the different modules and functions. Function FindExamples(modsfolder:String) For m:dmod = EachIn modlist Local intro:String = Lower(ExtractDir(m.file)+"/doc/intro.html") Local stream = ReadFile(intro) If stream Local size = StreamSize(stream) If size>0 m.intro = ReadString(stream,size) m.intro = ReformatHTML(m.intro,True) Print m.name+" -> introduction found!" EndIf CloseFile stream EndIf FlushMem Next For f:dfunc = EachIn funlist Local example:String = Lower(ExtractDir(f.mymod.file)+"/doc/"+f.sname+".bmx") stream = ReadFile(example) If stream size = StreamSize(stream) If size>0 f.exfile = example f.example = ReadString(stream,size) Print f.sname+" -> example found!" EndIf CloseFile stream EndIf FlushMem Next End Function ' ' Writes the module documents Function WriteModDocs() Local stream Local modsfolder:String = bmaxfolder+"mod" Local outfolder:String = destfolder+"doc/bmxmods" outfolder = StripSlash(outfolder) If FileType(outfolder) = 0 Assert CreateDir(outfolder),"Couldn't create destination folder!" EndIf Print "Scanning for modules..." ScanModFolder(modsfolder) Print "Scanning for examples..." FindExamples(modsfolder) For m:dmod = EachIn modlist m.docfile:String = Lower(ExtractDir(m.file)+"/doc/commands.html") Next ' ' Remove commands with no documentation If SKIP_NONDOCED For f:dfunc = EachIn funlist If f.rets.length = 0 And f.desc.length = 0 And f.about.length = 0 ListRemove(f.mymod.funclist,f) ListRemove(funlist,f) EndIf Next EndIf ' ' Sort out cross references For f:dfunc = EachIn funlist f.about = FixFunctionRefs(f.about,f.mymod) Next For m:dmod = EachIn modlist m.intro = FixFunctionRefs(m.intro,m) Next modlist.sort Print modlist.count()+" Modules found!" Print "Writing Commands.txt..." stream = WriteFile(bmaxfolder+"doc/bmxmods/commands.txt") If stream For f:dfunc = EachIn funlist relFile:String = f.mymod.docfile'GetRelativeFilename(bmaxfolder,f.mymod.docfile) relFile = relFile[Len(StripSlash(bmaxfolder))..] If f.keyword = False Print "RELFILE:"+relFile WriteLine(stream,f.name+"("+f.param+")|"+relFile+"#"+f.sname) Else WriteLine(stream,f.name+"|"+relFile+"#"+f.sname) EndIf Next CloseFile stream Else Notify "Couldn't write commands.txt" EndIf Print "Writing Module Documents..." ' ' Write module doc files For m:dmod = EachIn modlist destdir:String = ExtractDir(m.docfile) If FileType(destdir) = 0 If CreateDir(destdir) = False Notify("Couldn't create 'doc/' folder for module:~n~q"+m.name+"~q") EndIf EndIf stream = WriteFile(m.docfile) If stream ' html header WriteLine(stream,"<html>") WriteLine(stream,"<head>") relFile:String = GetRelativeFilename(ExtractDir(m.docfile),bmaxfolder+"doc/bmxmods/docs.css") WriteLine(stream,"<link rel=styleSheet href=~q"+relFile+"~q type='text/css'>") WriteLine(stream,"</head>") WriteLine(stream,"<body class=~qbody~q>") ' module name WriteLine(stream,"<table width=100% class=~qbody~q>") WriteLine(stream,"<tr><td class=~qmodulename~q><a href=~qfile://" + m.file +"~q> "+m.name+"</a></td></tr>") ' module intro WriteLine(stream,"<tr><td class=~qmoduleintro~q>"+m.intro+"</td></tr>") ' module functions If m.funclist.count()>0 m.funclist.sort WriteLine(stream,"<tr><td class=~qbody~q>") For f:dfunc = EachIn m.funclist WriteLine(stream,"<table class=~qfunctionbox~q><tr><td class=~qfunchead~q colspan=2 id=~q"+f.sname+"~q>") If f.keyword = False WriteLine(stream,f.name+"(<font class=~qfuncparam~q>"+f.param+"</font>)") Else WriteLine(stream,f.name) EndIf WriteLine(stream,"</td></tr>") If f.rets.length WriteLine(stream,"<tr><td class=~qfuncleft~q>Returns</td>") WriteLine(stream,"<td class=~qfuncright~q>"+f.rets+"</td></tr>") EndIf If f.desc.length WriteLine(stream,"<tr><td class=~qfuncleft~q>Short description</td>") WriteLine(stream,"<td class=~qfuncright~q>"+f.desc+"</td></tr>") EndIf If f.about.length WriteLine(stream,"<tr><td class=~qfuncleft~q>Long description</td>") WriteLine(stream,"<td class=~qfuncright~q>"+f.about+"</td></tr>") EndIf If f.example.length WriteLine(stream,"<tr><td class=~qfuncleft~q>Example</td>") relFile:String = GetRelativeFilename(ExtractDir(m.docfile),f.exfile) WriteLine(stream,"<td class=~qfuncright~q><a href=~q"+relFile+"~q target=~q_blank~q class=~qexample~q><pre>"+f.example+"</pre></a></td></tr>") EndIf ' ' Remember to fetch examples??? WriteLine(stream,"</table><br>") Next WriteLine stream,"</td></tr>" EndIf ' module info WriteLine(stream,"<tr><td class=~qbody~q>") Local out:String = "<table class=~qmodinfobox~q>"+linefeed+"<tr><td colspan=2 class=~qmodinfohead~q>Module Info</tr></td>"+linefeed+m.info+linefeed+"</table>" WriteLine(stream,out) WriteLine(stream,"</td></tr></table>") WriteLine(stream,"</body>") WriteLine(stream,"</html>") CloseFile stream Else Notify "Couldn't create output file:~n~q"+m.docfile+"~q" EndIf Next Print "Writing Navigation Document..." ' ' Write navigation file Local navfile:String = bmaxfolder+"doc/bmxmods/navbar.html" stream = WriteFile(navfile) If stream ' html header WriteLine(stream,"<html>") WriteLine(stream,"<head>") WriteLine(stream,"<link rel=styleSheet href=~qdocs.css~q type='text/css'>") WriteLine(stream,"<script>") WriteLine(stream,"// Do we use DOM or not?") WriteLine(stream,"var dom = (document.getElementById && !document.all)? 1: 0;") WriteLine(stream,"function toggle(the_id)") WriteLine(stream,"{") WriteLine(stream," var obj = (dom)? document.getElementById(the_id): document.all[the_id];") WriteLine(stream," if(obj.style.display == 'inline'){") WriteLine(stream," obj.style.visibility = 'hidden';") WriteLine(stream," obj.style.display = 'none';") WriteLine(stream," }else{") WriteLine(stream," obj.style.visibility = 'visible';") WriteLine(stream," obj.style.display = 'inline';") WriteLine(stream," }") WriteLine(stream,"}") WriteLine(stream,"</script>") WriteLine(stream,"</head>") WriteLine(stream,"<body>") ' module list WriteLine(stream,"<table width=~q200px~q><tr><td>") WriteLine(stream,"<div class=~qnav~q>By Module</div>") For m:dmod = EachIn modlist Local id:String = m.name.Replace(".","_") Local first = True For f:dfunc = EachIn m.funclist If first relFile:String = GetRelativeFilename(ExtractDir(navfile),m.docfile) WriteLine(stream,"<div class=~qnavmod~q><a class=~qnavmodlink~q onClick=~qtoggle('"+id+"')~q href=~q"+relFile+"~q target=~qmain~q>"+m.name+"</a></div>") WriteLine(stream,"<div id=~q"+id+"~q class=~qnavfunclist~q>") first = False EndIf WriteLine(stream,"<div class=~qnavfunc~q><a class=~qnavfunclink~q href=~q"+relFile+"#"+f.sname+"~q target=~qmain~q>"+f.sname+"</a></div>") Next If first = False WriteLine(stream,"</div>") EndIf Next WriteLine(stream,"</td></tr><tr><td>") ' alphabetical function list WriteLine(stream,"<div class=~qnav~q><br>Alphabetical</div>") funlist.sort alp:String = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ" For Local char:Int = 0 Until alp.length s:String = Chr(alp[char]) id:String = "Alpha_"+s first = True For f:dfunc = EachIn funlist If Upper(Chr(f.sname[0]))=s If first WriteLine(stream,"<div class=~qnavmod~q><a class=~qnavmodlink~q href=~qjavascript:toggle('"+id+"')~q>"+s+"</a></div>") WriteLine(stream,"<div id=~q"+id+"~q class=~qnavfunclist~q>") first = False EndIf relFile:String = GetRelativeFilename(ExtractDir(navfile),f.mymod.docfile) WriteLine(stream,"<div class=~qnavfunc~q><a class=~qnavfunclink~q href=~q"+relFile+"#"+f.sname+"~q target=~qmain~q>"+f.sname+"</a></div>") EndIf Next If first = False WriteLine(stream,"</div>") EndIf Next WriteLine(stream,"</td></tr></table>") WriteLine(stream,"</body>") WriteLine(stream,"</html>") CloseFile stream Else Notify "Couldn't create output file:~n~q"+navfile+"~q" EndIf WriteIndexFile(bmaxfolder+"doc/bmxmods/index.html") GenerateCSSFile(outfolder) End Function ' ' Write index.html file Function WriteIndexFile(indfile:String) Print "Writing Index Document..." stream = WriteFile(indfile) If stream WriteLine(stream,"<html><head>") WriteLine(stream,"<title>BlitzMax Command Reference</title>") WriteLine(stream,"</head>") WriteLine(stream,"<frameset cols='230,*'>") WriteLine(stream,"<frame src=~qnavbar.html~q name=~qnavbar~q><frame src=~qwelcome.html~q name=~qmain~q>") WriteLine(stream,"</frameset>") WriteLine(stream,"</html>") CloseFile stream Else Notify "Couldn't create output file:~n~q"+indfile+"~q" EndIf End Function ' ' Converts non module documents to the same style Function ConvertDocs() Local checkfolder:String[] = [bmaxfolder+"doc/bmxmods",bmaxfolder+"doc/bmxlang",bmaxfolder+"doc/bmxuser"] Local stream Local size Local folder:String Local files:String[] Local file:String Local fi:String Local s:String For folder = EachIn checkfolder ' ' Backup original html files BackupFolder(folder,["htm","html"]) files = LoadDir(folder,True) For fi = EachIn files file = folder+"/"+fi If FileType(file)=1 ' ' This file is an original html file that's ' been backed up. We use that to generate the new ' docs. If file.find(backuppre)=>0 Local f1:Int = file.find(backuppre) Local targetfile:String = file[0..f1]+file[f1+backuppre.length..file.length] stream = ReadFile(file) If stream size = StreamSize(stream) If size>0 s:String = ReadString(stream,size) EndIf CloseFile stream If targetfile.find("navbar")=>0 ' Navigation bar s = ReformatNavbar(s) stream = WriteFile(targetfile) If stream ' html header WriteLine(stream,"<html>") WriteLine(stream,"<head>") WriteLine(stream,"<link rel=styleSheet href=~qdocs.css~q type='text/css'>") WriteLine(stream,"<script>") WriteLine(stream,"// Do we use DOM or not?") WriteLine(stream,"var dom = (document.getElementById && !document.all)? 1: 0;") WriteLine(stream,"function toggle(the_id)") WriteLine(stream,"{") WriteLine(stream," var obj = (dom)? document.getElementById(the_id): document.all[the_id];") WriteLine(stream," if(obj.style.display == 'inline'){") WriteLine(stream," obj.style.visibility = 'hidden';") WriteLine(stream," obj.style.display = 'none';") WriteLine(stream," }else{") WriteLine(stream," obj.style.visibility = 'visible';") WriteLine(stream," obj.style.display = 'inline';") WriteLine(stream," }") WriteLine(stream,"}") WriteLine(stream,"</script>") WriteLine(stream,"</head>") WriteLine(stream,"<body>") ' nav list WriteLine(stream,"<table width=~q200px~q><tr><td>") WriteLine(stream,s) WriteLine(stream,"</td></tr></table>") WriteLine(stream,"</body>") WriteLine(stream,"</html>") CloseFile stream Else Notify "Unable to write file:~n~q"+targetfile+"~q!",True End EndIf Else ' Regular html doc s = ReformatHTML(s) stream = WriteFile(targetfile) If stream ' html header WriteLine(stream,"<html>") WriteLine(stream,"<head>") WriteLine(stream,"<link rel=styleSheet href=~qfile://"+folder+"/docs.css~q type='text/css'>") WriteLine(stream,"</head>") WriteLine(stream,"<body class=~qbody~q>") WriteLine(stream,"<table width=95% class=~qbody~q>") WriteLine(stream,"<tr><td class=~qmoduleintro~q>") WriteString(stream,s) WriteLine(stream,"</td></tr></table>") WriteLine(stream,"</body>") WriteLine(stream,"</html>") CloseFile stream Else Notify "Unable to write file:~n~q"+targetfile+"~q!",True End EndIf EndIf EndIf EndIf EndIf Next GenerateCSSFile(folder) WriteIndexFile(folder+"/index.html") Next End Function ' ' Backups all files with certain extensions in a folder Function BackupFolder(folder:String,extensions:String[]) Local backitup:Int Local fi:String Local file:String Local ext:String Local files:String[] files = LoadDir(folder,True) For fi = EachIn files file = folder+"/"+fi If FileType(file)=1 If file.find(backuppre)<0 backitup = False If extensions.length = 0 backitup = True EndIf For ext = EachIn extensions If Lower(ExtractExt(file)) = ext backitup = True EndIf Next If backitup If BackupFile(file) Print "Backing up: ~q"+file+"~q..." EndIf EndIf EndIf EndIf FlushMem Next End Function ' ' Backups a single file, only if a backup doesn't already exist, ' unless the force flag is set Function BackupFile(file:String,force:Int=False) Local backupfile:String = ExtractDir(file)+"/"+backuppre+StripDir(file) If FileType(backupfile) = 0 Or force = True Local stream = ReadFile(file) If stream Local size = StreamSize(stream) If size>0 Local s:String = ReadString(stream,size) EndIf CloseFile stream stream = WriteFile(backupfile) If stream WriteString(stream,s) CloseFile stream Else Notify "Unable to backup file:~n~q"+file+"~q!",True End EndIf Else Return False EndIf Else Return False EndIf Return True End Function ' ' Creates a CSS file containing a style sheet Function GenerateCSSFile(outfolder:String) Print "Writing CSS Document..." Local c:CSS_Class ClearList(CSS_List) Local cssfile:String = outfolder+"/docs.css" stream = WriteFile(cssfile) If stream c:CSS_Class = New CSS_Class c.name = ".body" c.background = "#FFFFFF" c.border = "0px" c.font = "10pt helvetica" c.width = "100%" c:CSS_Class = New CSS_Class c.name = ".modulename" c.font = "20pt helvetica" c.background = "#FFFFFF" c.border_bottom = "20px solid #FFFFFF" c.width = "100%" c:CSS_Class = New CSS_Class c.name = ".moduleintro" c.font = "10pt helvetica" c.background = "#FFFFFF" c.border_bottom = "20px solid #FFFFFF" c.padding_left = "20px" c.width = "100%" c:CSS_Class = New CSS_Class c.name = ".moduleintrohead" c.font = "15pt helvetica" c.padding_left = "0px" c:CSS_Class = New CSS_Class c.name = ".functionbox" c.padding_top = "20px" c.font = "10pt helvetica" c.width = "100%" c:CSS_Class = New CSS_Class c.name = ".funchead" c.padding = "10px" c.background = "#CCDDEE" c.border_bottom = "1px Solid #BBCCDD" c.font_weight = "bold" c.width = "100%" c:CSS_Class = New CSS_Class c.name = ".funcname" c.font_style = "normal" c.font_weight = "bold" c:CSS_Class = New CSS_Class c.name = ".funcparam" c.font_style = "italic" c.font_weight = "normal" c:CSS_Class = New CSS_Class c.name = ".funcleft" c.font_weight = "normal" c.padding = "10px" c.font = "8pt helvetica" c.background = "#CCDDEE" c.border_bottom = "1px solid #BBCCDD" c.width = "15%" c.v_align = "text-top" c:CSS_Class = New CSS_Class c.name = ".funcright" c.font = "10pt helvetica" c.font_style = "normal" c.font_weight = "normal" c.background = "#DDEEFF" c.border_bottom = "1px solid #CCDDEE" c.padding = "10px" c.width = "85%" ' ' ' Module info box c:CSS_Class = New CSS_Class c.name = ".modinfobox" c.width = "100%" c:CSS_Class = New CSS_Class c.name = ".modinfohead" c.background = "#CCDDEE" c.border_bottom = "1px solid #BBCCDD" c.font = "8pt helvetica" c.padding = "10px" c.font = "10pt helvetica" c.font_weight = "bold" c.width = "100%" c:CSS_Class = New CSS_Class c.name = ".modinfoleft" c.background = "#CCDDEE" c.border_bottom = "1px solid #BBCCDD" c.font = "8pt helvetica" c.padding_left = "10px" c.width = "15%" c:CSS_Class = New CSS_Class c.name = ".modinforight" c.background = "#DDEEFF" c.font = "8pt helvetica" c.border_bottom = "1px solid #CCDDEE" c.padding_left = "10px" c.width = "85%" ' ' ' Navigation Bar c:CSS_Class = New CSS_Class c.name = ".nav" c.font = "10pt helvetica" c.width = "100%" c.border_top = "2px solid #FFFFFF" c.padding = "0px" c:CSS_Class = New CSS_Class c.name = ".navfunclist" c.display = "none" c.visibility = "hidden" c.font = "10pt helvetica" c.border = "0px" c:CSS_Class = New CSS_Class c.name = ".navmod" c.background = "#CCDDEE" c.border_top = "2px solid #FFFFFF" c.border_bottom = "1px solid #BBCCDD" c.font = "10pt helvetica" c.padding_left = "10px" c:CSS_Class = New CSS_Class c.name = ".navfunc" c.padding_left = "20px" c.background = "#DDEEFF" c.border_top = "2px solid #FFFFFF" c.border_bottom = "1px solid #CCDDEE" ' ' Table stuff c:CSS_Class = New CSS_Class c.name = ".subtable" c.font = "10pt helvetica" c.background = "#FFFFFF" c:CSS_Class = New CSS_Class c.name = ".subth" c.font = "10pt helvetica" c.font_weight = "bold" c.text_align = "left" c.background = "#CCDDEE" c.border_bottom = "1px solid #BBCCDD" c.padding_left = "10px" c.padding_right = "10px" c:CSS_Class = New CSS_Class c.name = ".subtd" c.font = "10pt helvetica" c.font_weight = "normal" c.text_align = "left" c.background = "#DDEEFF" c.border_top = "0px solid #FFFFFF" c.border_bottom = "1px solid #CCDDEE" c.padding_left = "10px" c.padding_right = "10px" ' ' Hyperlink stuff c:CSS_Class = New CSS_Class c.name = "a" c.color = "#000000" c:CSS_Class = New CSS_Class c.name = "a:hover" c.color = "#445566" c:CSS_Class = New CSS_Class c.name = "a.navmodlink" c.font_weight = "bold" c.width = "100%" c.text_decoration = "none" c:CSS_Class = New CSS_Class c.name = "a.navfunclink" c.text_decoration = "none" c.width = "100%" c:CSS_Class = New CSS_Class c.name = "a.example" c.color = "#000000" c.text_decoration = "none" c.width = "100%" c:CSS_Class = New CSS_Class c.name = "pre" c.padding = "10px" c.background = "#EEF8FF" For c:CSS_Class = EachIn CSS_List c.Write(stream) Next CloseFile stream Else Notify "Couldn't create output file:~n~q"+cssfile+"~q" EndIf End Function ' ' CSS_Class type, utillity class to ease writing of css files Type CSS_Class Field name:String Field display:String Field background:String Field cell_spacing:String Field border:String Field border_bottom:String Field border_left:String Field border_top:String Field border_right:String Field color:String Field padding:String Field padding_left:String Field padding_right:String Field padding_top:String Field padding_bottom:String Field font:String Field font_style:String Field font_weight:String Field text_decoration:String Field width:String Field max_width:String Field min_width:String Field height:String Field max_height:String Field min_height:String Field v_align:String Field text_align:String Field visibility:String Method New() CSS_List.addlast Self End Method Method Write(stream) WriteLine(stream,Self.name+" {") If Self.visibility.length Then WriteLine(stream," visibility: "+Self.visibility+";") If Self.display.length Then WriteLine(stream," display: "+Self.display+";") If Self.color.length Then WriteLine(stream," color: "+Self.color+";") If Self.font.length Then WriteLine(stream," font: "+Self.font+";") If Self.font_style.length Then WriteLine(stream," font-style: "+Self.font_style+";") If Self.font_weight.length Then WriteLine(stream," font-weight: "+Self.font_weight+";") If Self.text_decoration.length Then WriteLine(stream," text-decoration: "+Self.text_decoration+";") If Self.width.length Then WriteLine(stream," width: "+Self.width+";") If Self.max_width.length Then WriteLine(stream," max-width: "+Self.max_width+";") If Self.min_width.length Then WriteLine(stream," min-width: "+Self.min_width+";") If Self.height.length Then WriteLine(stream," height: "+Self.height+";") If Self.max_height.length Then WriteLine(stream," max-height: "+Self.max_height+";") If Self.min_height.length Then WriteLine(stream," min-height: "+Self.min_height+";") If Self.background.length Then WriteLine(stream," background: "+Self.background+";") If Self.border.length Then WriteLine(stream," border: "+Self.border+";") If Self.border_bottom.length Then WriteLine(stream," border-bottom: "+Self.border_bottom+";") If Self.border_left.length Then WriteLine(stream," border-left: "+Self.border_left+";") If Self.border_right.length Then WriteLine(stream," border-right: "+Self.border_right+";") If Self.border_top.length Then WriteLine(stream," border-top: "+Self.border_top+";") If Self.padding.length Then WriteLine(stream," padding: "+Self.padding+";") If Self.padding_bottom.length Then WriteLine(stream," padding-bottom: "+Self.padding_bottom+";") If Self.padding_left.length Then WriteLine(stream," padding-left: "+Self.padding_left+";") If Self.padding_right.length Then WriteLine(stream," padding-right: "+Self.padding_right+";") If Self.padding_top.length Then WriteLine(stream," padding-top: "+Self.padding_top+";") If Self.cell_spacing.length Then WriteLine(stream," cell-spacing: "+Self.cell_spacing+";") If Self.v_align.length Then WriteLine(stream," vertical-align: "+Self.v_align+";") If Self.text_align.length Then WriteLine(stream," text-align: "+Self.text_align+";") WriteLine(stream,"}") WriteLine(stream,"") End Method End Type ' ' Convert normal docs :) ConvertDocs() ' ' Write the Module docs :) WriteModDocs() Print "Finished!"