//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("

\n"); context.Heading(1, comment); context.Write("

\n"); context.m_lib = comment; }; context.m_sections[`\function`] = function(comment, context) { comment = comment.TrimLeft().TrimRight(); // trim parenthesis context.Write("
\n"); context.Write(format(``,context.m_lib,comment)); context.Heading(3, comment); context.Write(``); context.XMLWrite(format(``, context.m_lib, comment)); }; context.m_sections[`\brief`] = function(comment, context) { context.Write(format("Brief:%s
", comment)); }; context.m_sections[`\param`] = function(comment, context) { context.Write(format("Param:%s
", comment)); }; context.m_sections[`\return`] = function(comment, context) { context.Write(format("Return:%s
", comment)); }; context.m_sections[`\sa`] = function(comment, context) { context.Write(format("See Also:%s
", comment)); }; context.Heading = function(number, string) { .m_htmlOut.WriteString(format("%s\n", number, string, number)); }; context.m_sections[`\this`] = function(comment, context) { context.Write(format("This:%s
", comment)); }; context.Paragraph = function(string) { .m_htmlOut.WriteString(format("

%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(""); // if(context.m_htmlOut.Open(filename, 0)) { // write html head context.Write("GM Documentation"); foreach(file in .m_files) { fp = system.File(); if(fp.Open(file)) { print(`Documenting`, file, `...`); .ExtractCommentStrings(fp,.CommentHandler,context); fp.Close(); } } context.XMLWrite(""); if(context.m_xmlOut) { context.m_xmlOut.Close(); } context.Write(""); 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.`);