//debug();
//
// This program generates html documentation for script functions.
// It merely converts comments with a certain syntax into documentation.
// Example:
//
// /*gm
// \lib Library Name
// */
//
// /*gm
// \function Function name
// \brief Brief description of function
// \param Parameter description, you should describe type information
// \return Return value description
// */
//
//
// \function CreateGMDocumenter
//
global CreateGMDocumenter = function()
{
documenter = table
(
// \function ExtractGmCommentStrings
// \param fp is source file handle
// \param commentHandler is a function taking 2 params, comment string and context
// \param context is passed to comment handler
ExtractCommentStrings = function(fp, commentHandler, context)
{
openGmComment = "/*gm";
openGmCommentLen = openGmComment.Length();
closeGmComment = "*/";
closeGmCommentLen = closeGmComment.Length();
line = fp.ReadLine();
while(line)
{
pos = line.Find(openGmComment);
while(pos >= 0)
{
pos = pos + openGmCommentLen;
line = line.Right(line.Length() - pos);
comment = "";
// eat up lines untill end of comment
pos = line.Find(closeGmComment);
while(pos < 0)
{
comment = comment + line;
line = fp.ReadLine();
if(line == null)
{
pos = 0;
}
else
{
pos = line.Find(closeGmComment);
}
}
if(line)
{
comment = comment + line.Left(pos);
line = line.Right(line.Length() - (pos + closeGmCommentLen));
pos = line.Find(openGmComment);
}
else
{
pos = -1;
}
if(comment.Length() > 0)
{
// process comment string
comment = comment.ReplaceCharsInSet(' ', "\r\n\v");
commentHandler(comment, context);
}
}
line = fp.ReadLine();
}
},
// \function CommentHandler
// \param comment is an incoming comment string
// \param context is a table with a m_sections table where each m_section
// is a function taking the section string and the context
// context also has a BeginComment() call
CommentHandler = function(comment, context)
{
if(comment and comment.Length())
{
commentSet = table();
foreach(section and sectionHandler in context.m_sections)
{
search = comment;
sectionStart = search.Find(section);
sectionLength = section.Length();
offset = 0;
while(sectionStart >= 0)
{
commentSet[offset + sectionStart] = section;
offset = offset + sectionLength;
search = search.Right(search.Length() - sectionLength);
sectionStart = search.Find(section);
}
}
// commentSet is now a table containing the start positions of each comment bit.
length = comment.Length();
local j;
for(i = 0; i < length; i = i + 1)
{
if(commentSet[i])
{
// find the next comment...
for(j = i + 1; j < length; j = j + 1)
{
if(commentSet[j] or j == (length - 1))
{
section = commentSet[i];
sectionLength = section.Length();
first = i + sectionLength;
count = (j - i) - sectionLength;
subComment = comment.Mid(first, count);
context.m_sections[section](subComment, context);
break;
}
}
}
}
}
},
m_files = table(),
// \function AddFile will add a file to be documented
AddFile = function(filename)
{
.m_files[tableCount(.m_files)] = filename;
},
// \function CreateDocumentation will create documentation for all added files
// \param path is the output path for the resulting .html docco
CreateDocumentation = function(filename)
{
context = table();
context.m_sections = table();
context.m_htmlOut = system.File();
context.m_xmlOut = system.File();
context.m_lib = "";
context.m_sections[`\lib`] = function(comment, context)
{
comment = comment.TrimLeft().TrimRight();
// trim parenthesis
context.Write("
%s
\n", string)); }; context.Write = function(string) { .m_htmlOut.WriteString(string); }; context.XMLWrite = function(string) { if(.m_xmlOut) { .m_xmlOut.WriteString(string); } }; xmlFilename = filename.SetExtension("xml"); if(!context.m_xmlOut.Open(xmlFilename, 0)) { print("** ERROR: Failed to open XML output file '",xmlFilename,"' ! **"); context.m_xmlOut = null; } context.XMLWrite(``); context.XMLWrite("