/Articles/Forth/PHP/GenerateHTML.php
0,0 → 1,511
<?php
// This PHP script generates clickable HTML documentation files for amforth
// project. Script should be run once (offline) when new versions of sorces are
// stored. It creates new subdirectory with HTML documentation tree.
//
// Configuration file is GenerateHTML.cfg
//
// (c)miho 2007 / http://www.mlab.cz
 
// **********************************************************************
// History
// **********************************************************************
// 0.00 work wersion
 
 
// **********************************************************************
// 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 MyReadFile($FileName, &$FileContent)
// Reads file, returns file as a single string
{
// Read file
$FileContent=@file($FileName);
 
// Test if file contains any content
if ($FileContent==FALSE)
{
unset($FileContent);
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 SourceAsm($SourceDir, $FileName, &$SourceAsmFiles, &$LabelList )
// Process ASM source file, recurse all includes
// 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!="")
{
print $Error."\n";
return 1;
}
// 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="";
}
SourceAsm($SourceDir, $Dir.$Value, $SourceAsmFiles, $LabelList);
}
unset($Includes);
}
 
// End
return 0;
}
 
 
function PrintSourceAsm(&$SourceAsmFiles)
// Prints all procesed ASM files
{
print "Asm Source File List\n";
foreach($SourceAsmFiles as $Key => $Value)
{
print " ".$Value."\n";
}
print "\n";
}
 
 
function PrintLabels(&$LabelList)
// Prints all found labels
{
print "Label List\n";
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
// IN $LabelList - Found labels
// OUT $WordList - Word List (ShortLabel, Word, Comment, Label, FileName)
{
 
print "Word List\n";
if ($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($SourceDir.$FileName, $FileContent);
if ($Error!="")
{
print " ".$Error."\n";
return 1;
}
$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";
}
 
 
function GenerateWordList($TemplateDir, $DestinationDir, &$LabelList, &$WordList)
// Creates HTML pages with Word List
// 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";
foreach (glob($TemplateDir."WordList.*.html") as $FileName)
{
// Process template file
print " Temlate $FileName\n";
 
// Read template file
$Error=MyReadFileString($FileName, $FileContent);
if ($Error!="")
{
print " ".$Error."\n";
return 1;
}
 
// Find <<WordList>>
if (!preg_match("/( *)(<<WordList>>)/i",$FileContent,$Matches))
{
print " Missing <<WordList>> in template file\n";
unset($FileContent);
return -1;
}
$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
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)
{
$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!="")
{
print " ".$Error."\n";
return -1;
}
 
// Clear memory
unset($FileContent);
unset($WordListHTML);
}
 
// Delimiter
print "\n";
}
 
 
function GenerateAsmFiles($TemplateDir, $SourceDir, &$SourceAsmFiles, $DestinationDir)
// Cretaes HTML files from all processed ASM files
// IN
//
{
// Info
print "Copy ASM Files\n";
 
// Destination directory exists
$DestinationDir.=ASMFILES;
if (!is_dir($DestinationDir))
{
if (!@mkdir($DestinationDir))
{
print " Unable Create Dir ".$DestinationDir."\n";
return -1;
}
}
// Read template
$Error=MyReadFileString($TemplateDir."FileAsm.en.html", $Template);
if ($Error!="")
{
print " ".$Error."\n";
return -1;
}
 
// Copy all source files
foreach($SourceAsmFiles as $Key => $FileName)
{
print " ".$FileName."\n";
 
// Read ASM file
$Error=MyReadFileString($SourceDir.$FileName, $FileContent);
if ($Error!="")
{
print " ".$Error."\n";
return 1;
}
 
// 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!="")
{
print " ".$Error."\n";
return -1;
}
}
// Delimiter
print "\n";
}
 
 
// **********************************************************************
// Main Block
// **********************************************************************
 
 
// This file contains configurations for this script
require_once("GenerateHTML.cfg");
 
 
// Global Like Variables
//$SourceAsmFiles - All processed ASM files (filenames)
//$LabelList - All label definitions (Label, FileName, LineNumber)
//$WordList - Word List (ShortLabel, Word, Comment, Label, FileName)
 
 
// Process all ASM files from the root level
SourceAsm($CFG_SourceDir, $CFG_SourceAsm, $SourceAsmFiles, $LabelList);
PrintSourceAsm($SourceAsmFiles);
PrintLabels($LabelList);
 
// Destilate Labels and Words
CreateWordList($CFG_SourceDir, $LabelList, $WordList);
 
// Create HTML WordList
GenerateWordList($CFG_TemplateDir, $CFG_DestinationDir, $LabelList, $WordList);
 
// Copy ASM files and convert them into HTML
GenerateAsmFiles($CFG_TemplateDir, $CFG_SourceDir, $SourceAsmFiles, $CFG_DestinationDir);
 
 
// Zpracování readme autora + verze
 
// 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)
// Ctělo by to do stránek vkládat info o verzi a (c)
?>