You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
334 lines
8.5 KiB
334 lines
8.5 KiB
1 year ago
|
//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("<BR><HR>\n");
|
||
|
context.Heading(1, comment);
|
||
|
context.Write("<HR><BR>\n");
|
||
|
context.m_lib = comment;
|
||
|
};
|
||
|
context.m_sections[`\function`] = function(comment, context)
|
||
|
{
|
||
|
comment = comment.TrimLeft().TrimRight();
|
||
|
// trim parenthesis
|
||
|
|
||
|
context.Write("<HR>\n");
|
||
|
context.Write(format(`<a name="%s::%s">`,context.m_lib,comment));
|
||
|
context.Heading(3, comment);
|
||
|
context.Write(`</a>`);
|
||
|
context.XMLWrite(format(`<function name="%s::%s"/>`, context.m_lib, comment));
|
||
|
};
|
||
|
context.m_sections[`\brief`] = function(comment, context)
|
||
|
{
|
||
|
context.Write(format("<B><EM>Brief:</B></EM>%s<BR>", comment));
|
||
|
};
|
||
|
context.m_sections[`\param`] = function(comment, context)
|
||
|
{
|
||
|
context.Write(format("<B><EM>Param:</B></EM>%s<BR>", comment));
|
||
|
};
|
||
|
context.m_sections[`\return`] = function(comment, context)
|
||
|
{
|
||
|
context.Write(format("<B><EM>Return:</B></EM>%s<BR>", comment));
|
||
|
};
|
||
|
context.m_sections[`\sa`] = function(comment, context)
|
||
|
{
|
||
|
context.Write(format("<B><EM>See Also:</B></EM>%s<BR>", comment));
|
||
|
};
|
||
|
context.Heading = function(number, string)
|
||
|
{
|
||
|
.m_htmlOut.WriteString(format("<H%d>%s</H%d>\n", number, string, number));
|
||
|
};
|
||
|
context.m_sections[`\this`] = function(comment, context)
|
||
|
{
|
||
|
context.Write(format("<B><EM>This:</B></EM>%s<BR>", comment));
|
||
|
};
|
||
|
context.Paragraph = function(string)
|
||
|
{
|
||
|
.m_htmlOut.WriteString(format("<P>%s</P>\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(`<?xml version="1.0" encoding="utf-8"?>`);
|
||
|
context.XMLWrite("<functions>");
|
||
|
|
||
|
//
|
||
|
if(context.m_htmlOut.Open(filename, 0))
|
||
|
{
|
||
|
// write html head
|
||
|
context.Write("<HTML><HEAD><TITLE>GM Documentation</TITLE></HEAD><BODY>");
|
||
|
foreach(file in .m_files)
|
||
|
{
|
||
|
fp = system.File();
|
||
|
if(fp.Open(file))
|
||
|
{
|
||
|
print(`Documenting`, file, `...`);
|
||
|
|
||
|
.ExtractCommentStrings(fp,.CommentHandler,context);
|
||
|
|
||
|
fp.Close();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
context.XMLWrite("</functions>");
|
||
|
if(context.m_xmlOut)
|
||
|
|
||
|
{
|
||
|
context.m_xmlOut.Close();
|
||
|
}
|
||
|
|
||
|
context.Write("</BODY></HTML>");
|
||
|
context.m_htmlOut.Close();
|
||
|
}
|
||
|
}
|
||
|
);
|
||
|
|
||
|
return documenter;
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
* Entry Point
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
print("Starting GMDoc...");
|
||
|
|
||
|
inFile = arg[0]; // directory/file listings of 'to be documented' files
|
||
|
outFile = arg[1]; // ouput help files
|
||
|
|
||
|
documenter = CreateGMDocumenter();
|
||
|
|
||
|
dirsFile = system.File();
|
||
|
|
||
|
if(!dirsFile.Open(inFile, 1))
|
||
|
{
|
||
|
print("** Failed to open input file! **");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nextLine = dirsFile.ReadLine();
|
||
|
|
||
|
while(nextLine)
|
||
|
{
|
||
|
nextLine = nextLine.TrimRight(); // carriage return syndrome
|
||
|
|
||
|
path = nextLine;
|
||
|
filename = nextLine.GetFilename();
|
||
|
pos = filename.Find(".cpp",filename.Length() - 5);
|
||
|
|
||
|
if(pos >= 0) // doc file
|
||
|
{
|
||
|
if(system.FileExists(path))
|
||
|
{
|
||
|
documenter.AddFile(path);
|
||
|
}
|
||
|
}
|
||
|
else // doc directory
|
||
|
{
|
||
|
handle = system.FileFindFirst(path ^ `\*.*`);
|
||
|
while(handle)
|
||
|
{
|
||
|
extension = handle.filename.GetExtension().Lower();
|
||
|
print(extension);
|
||
|
if(extension == `cpp` or extension == `gm`)
|
||
|
{
|
||
|
if(system.FileExists(path ^ handle.filename))
|
||
|
{
|
||
|
documenter.AddFile(path ^ handle.filename);
|
||
|
}
|
||
|
}
|
||
|
handle = system.FileFindNext(handle);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
nextLine = dirsFile.ReadLine(); // read next line
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dirsFile.Close();
|
||
|
|
||
|
documenter.CreateDocumentation(outFile);
|
||
|
|
||
|
print(`Done.`);
|
||
|
|
||
|
|
||
|
|