|
|
//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.`);
|