<?php
// This PHP script generates clickable HTML documentation files for amforth
// project. Script should be run once (offline) when new versions of sorces are
// available. It creates new subdirectory with HTML documentation tree.
//
// Default configuration is in file GenerateHTML.cfg
//
// Command Line paramaters are available via php GenerateHTML.php --help
//
// (c)miho 2007 / http://www.mlab.cz
// **********************************************************************
// History
// **********************************************************************
// 0.00 work wersion
// 0.01 basic functionality
// **********************************************************************
// Definitions/parameters
// **********************************************************************
define ('INCLUDE_PATTERN', "/^ *\.include +\"(\S+)\"/i");
define ('LABEL_PREFIX', "(VE_|XT_|PFA)");
define ('LABEL_PATTERN', "/^ *(".LABEL_PREFIX."\S+):/i");
define ('WORD_PATTERN', "/((?:\\n *;.*)*)\\n *VE_Q:[^\\n]*\\n? *.db +[^,]* *, *(\S[^\\n|;]+)/im"); // Q is used instead of Word
define ('ASMFILES', "CodeAsm/");
// **********************************************************************
// Generic Funcions
// **********************************************************************
function Error($ErrorStr)
// If ErrorStr is not empty print it and die
{
if ($ErrorStr=="")
return;
print "\n";
print " ERROR: -->".$ErrorStr."\n";
die(1);
}
function MyReadFile($FileName, &$FileContent)
// Reads file, returns file as a single string
{
//
if ($FileName=="")
return "No File Name";
// Read file
$FileContent=@file($FileName);
// Test if file contains any content
if ($FileContent==FALSE)
return "No Data in File: $FileName";
// Remove CR or LF or CR/LF
foreach($FileContent as $Key => $Line)
{
$FileContent[$Key]=rtrim($Line);
}
// No error
return "";
}
function MyReadFileString($FileName, &$FileContent)
// Reads file and returns its content as a single string
{
// No Error
$Error="";
// Read file
$Error=MyReadFile($FileName, &$FileContent);
// Convert to a single string
if ($Error=="") $FileContent=implode("\n",$FileContent);
// Finished
return $Error;
}
function MyWriteFile($FileName, $FileContent)
// Creates and writes file
{
// Create Output File
$File=@fopen($FileName,"w");
if ($File==FALSE)
{
return "Unable Write File ".$FileName;
}
// Write content
fwrite($File,$FileContent);
fclose($File);
// No Error
return "";
}
function FileName2HTML($FileName)
// Converts FileName to FileName of HTML file
{
// Remove path
$FileName=basename($FileName);
// Change suffix
$FileName=preg_replace("/\.asm$/i",".html",$FileName);
// Finished
#print $FileName;
return $FileName;
}
function Label2Link($Link, $href, $title, &$LabelList)
// Converts Label to Link
// If label not found returns original text
// IN $Link - label to find
// IN $Word - word to show (on mouse)
// IN $LabelList - list of all labels (Label, FileName, LineNumber)
{
// Find label in $LabelList
foreach($LabelList as $Value)
{
if ($Link===$Value["Label"])
{
#$LabelListItem=$Value /////////////////////////////
print "Found ".$Value["Label"]."\n";
}
}
$FileName=$Value["FileName"]."#".$Link;
// Create link
$Link="<a href=\"".$FileName."\" title=\" ".$Word."\">".$Link.'</a>';
return $Link;
}
// **********************************************************************
// Function for processing
// **********************************************************************
function Help()
// Display help
{
print "\n";
print "This script takes default parameters from GenerateHTML.cfg.\n";
print "\n";
print "Parameters can be entered directly on command line as well:\n";
print " php GenerateHTML.php par1=val1 par2=val2\n";
print "\n";
print "Sometimes (in Windows) it is necessary to use quotation marks this way:\n";
print " php GenerateHTML.php \"par1=val1\" \"par2=val2\"\n";
print "\n";
print "Parameters are: \n";
print " EnableApache={0|1} - Enable to run in Apache\n";
print " SourceDir=path - path to asm source directory\n";
print " SourceAsm=file - name of top level asm source file\n";
print " SvnInfoFileName - name of Svn Info File\n";
print " TemplateDir=path - path to HTML template\n";
print " DestinationDir=path - path to destination HTML\n";
Error("\n");
}
function Parameters(&$CFG)
// Function process Command Line parameters
{
// Dummy values
$CFG["EnableApache"] = 0; // Do not allow run in Apache
$CFG["SourceDir"] = "";
$CFG["SourceAsm"] = "";
$CFG["SvnInfoFileName"] = "";
$CFG["TemplateDir"] = "";
$CFG["DestinationDir"] = "";
// Default values (in cfg file)
@include_once("GenerateHTML.cfg");
// Command Line parameters
if ($_SERVER["argc"]>1)
{
// Help
if ($_SERVER["argv"][1]=="--help")
Help();
// Drop
unset($_SERVER["argv"][0]);
// Go through arguments
foreach($_SERVER["argv"] as $Key => $Value)
{
$Left=substr($Value,0,strpos($Value,"="));
$Right=substr($Value,strpos($Value,"=")+1);
if (isset($CFG[$Left]) && $Right!="" )
{
$CFG[$Left]=$Right;
}
else
{
return "Invalid Parameter: $Value";
}
}
}
// Check if alowed to run in Apache
if ($_SERVER["argc"]==0 & ! $CFG["EnableApache"])
return "<b>This Script is configured so that it will not run in Apache.</b>";
// Info
print "Parameters\n";
// Correct paths and existence
foreach($CFG as $Key => $Value)
{
if (stripos($Key,"Dir"))
{
// Correct / at the end of path
if (substr($Value,strlen($Value)-1)!="/")
{
$CFG[$Key]=$Value."/";
}
// Check existence
#print "DIR".$CFG[$Key]."\n";
if ( ! is_dir($CFG[$Key]))
{
return "Directory does not exist: ".$Key."=".$CFG[$Key];
}
}
}
// Print info
if (count(CFG))
foreach($CFG as $Key => $Value)
print " $Key=$Value\n";
print "\n";
// No Error
return "";
}
function SourceAsm($SourceDir, $FileName, &$SourceAsmFiles, &$LabelList )
// Process ASM source file, recurse all includes
// Returns Error String
// Stores file names and labels into two arrays
// IN $SourceDir - base directory (not printed)
// IN $FileName - file to process
// OUT $SourceAsmFiles - list of all processed files (Filename)
// OUT $LabelList - list of all labels (Label, FileName, LineNumber)
{
// Start
print "Read Asm: $FileName\n";
// Read file
$Error=MyReadFile($SourceDir.$FileName, $FileContent);
if ($Error!="")
return $Error;
// Remember filename
$SourceAsmFiles[]=$FileName;
// Filter source file line by line - find labels
foreach($FileContent as $Key => $Value)
{
// Find label definitions
if (preg_match(LABEL_PATTERN,$Value,$Matches))
{
print " label @line ".($Key+1)." ".$Matches[1]."\n";
$LabelList[]=array("Label"=>$Matches[1],"FileName"=>$FileName,"LineNumber"=>($Key+1));
}
}
// Filter source file line by line - find includes
foreach($FileContent as $Key => $Value)
{
// Find .include "filename" lines
if (preg_match(INCLUDE_PATTERN,$Value,$Matches))
{
print " include @line ".($Key+1)." --> ".$Matches[1]."\n";
// Remember links
$Includes[]=$Matches[1];
}
}
// Print delimiter
print "\n";
// Recurse includes
if ($Includes)
{
foreach($Includes as $Value)
{
$Dir=dirname($FileName)."/";
if ($Dir=="./")
{
$Dir="";
}
$Error=SourceAsm($SourceDir, $Dir.$Value, $SourceAsmFiles, $LabelList);
if ($Error!="")
return $Error;
}
unset($Includes);
}
// End
return "";
}
function PrintSourceAsm(&$SourceAsmFiles)
// Prints all procesed ASM files
{
print "Asm Source File List\n";
if (count($SourceAsmFiles))
foreach($SourceAsmFiles as $Key => $Value)
{
print " ".$Value."\n";
}
print "\n";
}
function PrintLabels(&$LabelList)
// Prints all found labels
{
print "Label List\n";
if (count($LabelList))
foreach($LabelList as $Key => $Value)
{
print " ".$Value["Label"]." ".$Value["FileName"]." ".$Value["LineNumber"]."\n";
}
print "\n";
}
function CreateWordList($SourceDir, &$LabelList, &$WordList)
// Goes through LabelList and looks for word definitions
// Returns Error String
// IN $LabelList - Found labels
// OUT $WordList - Word List (ShortLabel, Word, Comment, Label, FileName)
{
print "Word List\n";
if (count($LabelList))
foreach ($LabelList as $Value)
{
// Take all VE definitions
if (stristr(substr($Value["Label"],0,3),"VE_"))
{
// Prepare Label without VE_
$ShortLabel=substr($Value["Label"],3);
// Prepare search pattern
$Pattern=str_replace("Q",$ShortLabel,WORD_PATTERN);
#print "Pattern: ".$Pattern." ".$Value["FileName"]."\n";
// Read source file
$FileName=$SourceDir.$Value["FileName"];
$Error=MyReadFileString($FileName, $FileContent);
if ($Error!="")
return $Error;
$FileContent="\n".$FileContent;
// Find label
if (preg_match($Pattern,$FileContent,$Matches))
{
// Coments - remove semiculomn
$Comment = rtrim(preg_replace("/\\n; ?(.*)/","$1\n",$Matches[1]));
// Convert .db parameters into string
$Word="";
#$Word=$Matches[2]." : ";
foreach(explode(",",$Matches[2]) as $Val)
{
// String element
preg_match("/^ *\"([^\"]*)(\" *)/",$Val,$Tmp);
#print "S:".$Tmp[1]."\n";
if ($Tmp[1]!="")
{
$Word.=$Tmp[1];
}
// Hexa number
preg_match("/\\$([0-9A-F]+)/i",$Val,$Tmp);
#print "H:".$Tmp[1]."\n";
if ($Tmp[1]!="")
{
$Number=hexdec($Tmp[1]);
if ($Number!=0)
$Word.=chr($Number);
}
// Decimal number
preg_match("/^([0-9]+)/i",$Val,$Tmp);
#print "D:".$Tmp[1]."\n";
if ($Tmp[1]!="")
{
$Number=$Tmp[1];
if ($Number!=0)
$Word.=chr($Number);
}
}
// Store label into array
$WordList[]=array("Word"=>$Word, "ShortLabel"=>$ShortLabel, "Comment"=>$Comment,
"Label"=>$Value["Label"] , "FileName"=>$Value["FileName"]
);
print " ".$Word." = ".$ShortLabel."\n";
if($Comment) print " ".preg_replace("/\\n/","\n ",$Comment)."\n";
}
// Sort Words
array_multisort($WordList);
// Clean Up
unset($FileContent);
}
}
print "\n";
return "";
}
function GenerateWordList($TemplateDir, $SvnInfoFileName, $DestinationDir, &$LabelList, &$WordList)
// Creates HTML pages with Word List
// Returns Error String
// IN $TemplateDir - template directory (file WordList.*.html)
// IN $LabelList - list of labels (Label, FileName, LineNumber)
// IN $WordList - list of words (ShortLabel, Word, Comment, Label, FileName)
// OUT WordList.*.html - create HTML pages (file WordList.*.html)
{
// Find all templates
print "Word List in HTML\n";
if (count(glob($TemplateDir."WordList.*.html")))
foreach (glob($TemplateDir."WordList.*.html") as $FileName)
{
// Process template file
print " Temlate $FileName\n";
// Read template file
$Error=MyReadFileString($FileName, $FileContent);
if ($Error!="")
return $Error;
// Find <<SvnInfo>>
if (!preg_match("/( *)(<<SvnInfo>>)/i",$FileContent,$Matches))
{
unset($FileContent);
return "Missing <<SvnInfo>> in template file";
}
$Indent=$Matches[1];
// Read Svn Info file
$Error=MyReadFileString($SvnInfoFileName, $SvnInfoFile);
if ($Error!="")
{
// We do not have Svn Info File
$SvnInfoFile="";
}
else
{
// We have Svn Info File
$SvnInfoFile=preg_replace("/^((?:URL|Repository|Last)[^:]*):(.*$)|^.*$/im","<tr><td>$1</td><td>$2</td></tr>",$SvnInfoFile);
$SvnInfoFile=preg_replace("~<tr><td></td><td></td></tr>\n~i","",$SvnInfoFile);
$SvnInfoFile="<tr><th colspan=\"2\">Subversion Info</th></tr>".$SvnInfoFile;
}
// Put Svn Info into HTML template
$FileContent=str_ireplace("<<SvnInfo>>", $SvnInfoFile, $FileContent);
#print $FileContent;
// Find <<WordList>>
if (!preg_match("/( *)(<<WordList>>)/i",$FileContent,$Matches))
{
unset($FileContent);
return "Missing <<WordList>> in template file";
}
$Indent=$Matches[1];
// Create HTML code - table header
$WordListHTML[]="<table>";
$WordListHTML[]=" <tr>";
$WordListHTML[]=" <th>Word</th>";
$WordListHTML[]=" <th>Label</th>";
$WordListHTML[]=" <th>Definition</th>";
$WordListHTML[]=" </tr>";
// Create HTML code - table lines
if (count($WordList))
foreach($WordList as $Key => $Value)
{
// Prepare (just for readibility)
$Word=$Value["Word"];
$Link="<a href=\"".ASMFILES.FileName2HTML($Value["FileName"])."#".$Value["ShortLabel"].
"\" title=\"".$Value["Label"]."\">".$Value["ShortLabel"]."</a>";
$Comment=$Value["Comment"];
// Generate HTML
$WordListHTML[]=" <tr>";
$WordListHTML[]=" <td>".htmlspecialchars($Word)."</td>";
$WordListHTML[]=" <td>".$Link."</td>";
$WordListHTML[]=" <td>".htmlspecialchars($Comment)."</td>";
$WordListHTML[]=" </tr>";
}
// Create HTML code - table end
$WordListHTML[]="</table>";
// Indent and Concatenate lines
foreach($WordListHTML as $Key => $Value)
{
if ($Key>0)
$WordListHTML[$Key]=$Indent.preg_replace("/\n/","<br>",$Value);
}
$WordListHTML=implode("\n",$WordListHTML);
// Put it into HTML template
$FileContent=str_ireplace("<<WordList>>", $WordListHTML, $FileContent);
#print $FileContent;
// Create Output File
$Error=MyWriteFile($DestinationDir.basename($FileName), $FileContent);
if ($Error!="")
return $Error;
// Clear memory
unset($FileContent);
unset($WordListHTML);
}
// Delimiter
print "\n";
return "";
}
function GenerateAsmFiles($TemplateDir, $SourceDir, &$SourceAsmFiles, $DestinationDir)
// Cretaes HTML files from all processed ASM files
// Returns Error String
// IN $TemplateDir - directory with template files
// IN $SourceDir - directory with asm source files
// OUT $SourceAsmFiles -
// IN $DestinationDir - directory for generated HTML files
{
// Info
print "Copy ASM Files\n";
// Destination directory exists
$DestinationDir.=ASMFILES;
if (!is_dir($DestinationDir))
if (!@mkdir($DestinationDir))
return "Unable Create Dir ".$DestinationDir;
// Read template
$Error=MyReadFileString($TemplateDir."FileAsm.en.html", $Template);
if ($Error!="")
return $Error;
// Copy all source files
foreach($SourceAsmFiles as $Key => $FileName)
{
print " ".$FileName."\n";
// Read ASM file
$Error=MyReadFileString($SourceDir.$FileName, $FileContent);
if ($Error!="")
return $Error;
// Prepare HTML
$FileContent=htmlspecialchars($FileContent);
$FileContent="<pre>\n".$FileContent."\n</pre>";
// Use Template
$TemplateWork=$Template;
$TemplateWork=str_ireplace("<<FileName>>", $FileName, $TemplateWork);
$TemplateWork=str_ireplace("<<FileContent>>", $FileContent, $TemplateWork);
// Write ASM file in HTML
$Error=MyWriteFile($DestinationDir.FileName2HTML($FileName), $TemplateWork);
if ($Error!="")
return $Error;
}
// Delimiter
print "\n";
return "";
}
// **********************************************************************
// Main Block
// **********************************************************************
// Global Like Variables (arrays)
// $CFG - Config parameters
// $SourceAsmFiles - All processed ASM files (filenames)
// $LabelList - All label definitions (Label, FileName, LineNumber)
// $WordList - Word List (ShortLabel, Word, Comment, Label, FileName)
// Process Command Line Parameters
Error(Parameters($CFG));
// Process all ASM files from the root level
Error(SourceAsm($CFG["SourceDir"], $CFG["SourceAsm"], $SourceAsmFiles, $LabelList));
PrintSourceAsm($SourceAsmFiles);
PrintLabels($LabelList);
// Destilate Labels and Words
Error(CreateWordList($CFG["SourceDir"], $LabelList, $WordList));
// Create HTML WordList
Error(GenerateWordList(
$CFG["TemplateDir"],
$CFG["SourceDir"].$CFG["SvnInfoFileName"],
$CFG["DestinationDir"],
$LabelList, $WordList));
// Copy ASM files and convert them into HTML
Error(GenerateAsmFiles($CFG["TemplateDir"], $CFG["SourceDir"], $SourceAsmFiles, $CFG["DestinationDir"]));
// Finish
print "O.K.\n";
return
// Zpracování readme autora
// Vyplatilo by se udělat samostatny formatovaci a nahrazovaci mechanizmus
// Zpracování templejtů do samostatného podprogramu (vyřešit indent...)
// tím se vyřeší i en/cs verze Asm souboru
// Generovat log do souboru místo printu (zvážit) oddělit chyby a varování
// Vyčistit cílový adresář
// Process all FORTH files
// Problém s rekurzí (potenciální nekonečno)
// Chtělo by to do stránek vkládat info o verzi a (c)
?>