//---------------------------------------------------------------------------
#include <fstream>
#include <vcl.h>
#include <registry.hpp>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
// CLASS PARAMETERS
//---------------------------------------------------------------------------
__fastcall Parameters::Parameters()
{
//Default values
Comment=new Code;
Comment->Color=clBlue;
Comment->Bold=false;
Comment->Italic=true;
Comment->Underline=false;
ReservedWord=new Code;
ReservedWord->Color=clBlack;
ReservedWord->Bold=true;
ReservedWord->Italic=false;
ReservedWord->Underline=false;
Preprocessor=new Code;
Preprocessor->Color=clGreen;
Preprocessor->Bold=false;
Preprocessor->Italic=true;
Preprocessor->Underline=false;
QuotedString=new Code;
QuotedString->Color= clRed;
QuotedString->Bold=false;
QuotedString->Italic=false;
QuotedString->Underline=false;
ReservedWords=new TStringList();
}
//---------------------------------------------------------------------------
__fastcall Parameters::~Parameters()
{
delete Comment;
delete ReservedWord;
delete Preprocessor;
delete QuotedString;
delete ReservedWords;
}
//---------------------------------------------------------------------------
void __fastcall Parameters::LoadFromReg()
{
TRegistry *AppReg=new TRegistry;
AppReg->RootKey=HKEY_CURRENT_USER;
if(AppReg->OpenKey("Software\\Michel Leunen\\Src2Html",false))
{
try
{
Comment->Color=static_cast<TColor>(AppReg->ReadInteger("Comment.Color"));
Comment->Bold=AppReg->ReadBool("Comment.Bold");
Comment->Italic=AppReg->ReadBool("Comment.Italic");
Comment->Underline=AppReg->ReadBool("Comment.Underline");
Preprocessor->Color=static_cast<TColor>(AppReg->ReadInteger("Preprocessor.Color"));
Preprocessor->Bold=AppReg->ReadBool("Preprocessor.Bold");
Preprocessor->Italic=AppReg->ReadBool("Preprocessor.Italic");
Preprocessor->Underline=AppReg->ReadBool("Preprocessor.Underline");
ReservedWord->Color=static_cast<TColor>(AppReg->ReadInteger("ReservedWord.Color"));
ReservedWord->Bold=AppReg->ReadBool("ReservedWord.Bold");
ReservedWord->Italic=AppReg->ReadBool("ReservedWord.Italic");
ReservedWord->Underline=AppReg->ReadBool("ReservedWord.Underline");
QuotedString->Color=static_cast<TColor>(AppReg->ReadInteger("QuotedString.Color"));
QuotedString->Bold=AppReg->ReadBool("QuotedString.Bold");
QuotedString->Italic=AppReg->ReadBool("QuotedString.Italic");
QuotedString->Underline=AppReg->ReadBool("QuotedString.Underline");
HtmlFont=AppReg->ReadString("HtmlFont");
ReservedWords->Clear();
ReservedWords->CommaText=AppReg->ReadString("ReservedWords");
}
catch (...)
{
}
}
delete AppReg;
}
//---------------------------------------------------------------------------
void __fastcall Parameters::SaveToReg()
{
TRegistry *AppReg=new TRegistry;
AppReg->RootKey=HKEY_CURRENT_USER;
AppReg->LazyWrite=false;
AppReg->OpenKey("Software\\Michel Leunen\\Src2Html",true);
AppReg->WriteInteger("Comment.Color",Comment->Color);
AppReg->WriteBool("Comment.Bold",Comment->Bold);
AppReg->WriteBool("Comment.Italic",Comment->Italic);
AppReg->WriteBool("Comment.Underline",Comment->Underline);
AppReg->WriteInteger("ReservedWord.Color",ReservedWord->Color);
AppReg->WriteBool("ReservedWord.Bold",ReservedWord->Bold);
AppReg->WriteBool("ReservedWord.Italic",ReservedWord->Italic);
AppReg->WriteBool("ReservedWord.Underline",ReservedWord->Underline);
AppReg->WriteInteger("Preprocessor.Color",Preprocessor->Color);
AppReg->WriteBool("Preprocessor.Bold",Preprocessor->Bold);
AppReg->WriteBool("Preprocessor.Italic",Preprocessor->Italic);
AppReg->WriteBool("Preprocessor.Underline",Preprocessor->Underline);
AppReg->WriteInteger("QuotedString.Color",QuotedString->Color);
AppReg->WriteBool("QuotedString.Bold",QuotedString->Bold);
AppReg->WriteBool("QuotedString.Italic",QuotedString->Italic);
AppReg->WriteBool("QuotedString.Underline",QuotedString->Underline);
AppReg->WriteString("HtmlFont",HtmlFont);
AppReg->WriteString("ReservedWords",ReservedWords->CommaText);
delete AppReg;
}
//---------------------------------------------------------------------------
// CLASS TFORM1
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Par=new Parameters();
Par->HtmlFont="Courier New";
Par->ReservedWords->Clear();
Par->ReservedWords->Assign(ReservedWordsComboBox->Items);
Par->LoadFromReg();
CodeListBox->ItemIndex=0;
//global variable used when parsing the source file
Comment=false;
}
//---------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
delete Par;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::SaveButtonClick(TObject *Sender)
{
if(SourceEdit->Text=="")
{
ShowMessage("Select a source file");
return;
}
//parse the source file
if(!ToHtml(SourceEdit->Text))
{
ShowMessage("Unable to load the source file!");
return;
}
Par->SaveToReg();
//Application->Terminate();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ChooseFileButtonClick(TObject *Sender)
{
OpenDialog->InitialDir=ExtractFileDir(Application->ExeName);
if(OpenDialog->Execute())
{
SourceEdit->Text=OpenDialog->FileName;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ChooseColorButtonClick(TObject *Sender)
{
switch (CodeListBox->ItemIndex)
{
case 0:
ColorDialog->Color=Par->Comment->Color;
break;
case 1:
ColorDialog->Color=Par->ReservedWord->Color;
break;
case 2:
ColorDialog->Color=Par->Preprocessor->Color;
break;
case 3:
ColorDialog->Color=Par->QuotedString->Color;
break;
default:
ShowMessage("Select an item in Code Listbox");
return;
}
if(ColorDialog->Execute())
{
switch (CodeListBox->ItemIndex)
{
case 0:
Par->Comment->Color=ColorDialog->Color;
break;
case 1:
Par->ReservedWord->Color=ColorDialog->Color;
break;
case 2:
Par->Preprocessor->Color=ColorDialog->Color;
break;
case 3:
Par->QuotedString->Color=ColorDialog->Color;
break;
}
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ChooseFontButtonClick(TObject *Sender)
{
FontDialog->Font->Name=Par->HtmlFont;
FontDialog->Font->Size=StrToInt(SizeEdit->Text);
if(FontDialog->Execute())
{
Par->HtmlFont=FontDialog->Font->Name;
SizeEdit->Text=IntToStr(FontDialog->Font->Size);
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::BoldCheckBoxClick(TObject *Sender)
{
switch (CodeListBox->ItemIndex)
{
case 0:
Par->Comment->Bold=BoldCheckBox->Checked;
break;
case 1:
Par->ReservedWord->Bold=BoldCheckBox->Checked;
break;
case 2:
Par->Preprocessor->Bold=BoldCheckBox->Checked;
break;
case 3:
Par->QuotedString->Bold=BoldCheckBox->Checked;
break;
default:
ShowMessage("Select an item in Code Listbox");
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ItalicCheckBoxClick(TObject *Sender)
{
switch (CodeListBox->ItemIndex)
{
case 0:
Par->Comment->Italic=ItalicCheckBox->Checked;
break;
case 1:
Par->ReservedWord->Italic=ItalicCheckBox->Checked;
break;
case 2:
Par->Preprocessor->Italic=ItalicCheckBox->Checked;
break;
case 3:
Par->QuotedString->Italic=ItalicCheckBox->Checked;
break;
default:
ShowMessage("Select an item in Code Listbox");
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::UnderlineCheckBoxClick(TObject *Sender)
{
switch (CodeListBox->ItemIndex)
{
case 0:
Par->Comment->Underline=UnderlineCheckBox->Checked;
break;
case 1:
Par->ReservedWord->Underline=UnderlineCheckBox->Checked;
break;
case 2:
Par->Preprocessor->Underline=UnderlineCheckBox->Checked;
break;
case 3:
Par->QuotedString->Underline=UnderlineCheckBox->Checked;
break;
default:
ShowMessage("Select an item in Code Listbox");
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::CodeListBoxClick(TObject *Sender)
{
switch (CodeListBox->ItemIndex)
{
case 0:
BoldCheckBox->Checked=Par->Comment->Bold;
ItalicCheckBox->Checked=Par->Comment->Italic;
UnderlineCheckBox->Checked=Par->Comment->Underline;
break;
case 1:
BoldCheckBox->Checked=Par->ReservedWord->Bold;
ItalicCheckBox->Checked=Par->ReservedWord->Italic;
UnderlineCheckBox->Checked=Par->ReservedWord->Underline;
break;
case 2:
BoldCheckBox->Checked=Par->Preprocessor->Bold;
ItalicCheckBox->Checked=Par->Preprocessor->Italic;
UnderlineCheckBox->Checked=Par->Preprocessor->Underline;
break;
case 3:
BoldCheckBox->Checked=Par->QuotedString->Bold;
ItalicCheckBox->Checked=Par->QuotedString->Italic;
UnderlineCheckBox->Checked=Par->QuotedString->Underline;
break;
default:
ShowMessage("Select an item in Code Listbox");
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::AddButtonClick(TObject *Sender)
{
if(ReservedWordsComboBox->Text!="")
{
ReservedWordsComboBox->Items->Add(ReservedWordsComboBox->Text);
Par->ReservedWords->Clear();
Par->ReservedWords->Assign(ReservedWordsComboBox->Items);
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::RemoveButtonClick(TObject *Sender)
{
if(ReservedWordsComboBox->ItemIndex!=-1)
{
ReservedWordsComboBox->Items->Delete(ReservedWordsComboBox->ItemIndex);
Par->ReservedWords->Clear();
Par->ReservedWords->Assign(ReservedWordsComboBox->Items);
}
}
//---------------------------------------------------------------------------
bool __fastcall TForm1::ToHtml(AnsiString FileName)
{
//load source file in a StringList
//each string corresponds to a source line
TStringList *Input=new TStringList;
try
{
Input->LoadFromFile(FileName);
}
catch(...)
{
return false;
}
//create a file whose name is the same as the source
//replace extension with .html
int Pos=FileName.AnsiPos(".");
AnsiString Ext=FileName.SubString(Pos+1,FileName.Length()-Pos);
AnsiString NewFileName=FileName.SubString(0,Pos-1)+"_"+Ext+".html";
TFileStream *Output=new TFileStream(NewFileName,fmCreate);
//write html header
AnsiString Buffer=WriteHeader();
Output->Write(Buffer.c_str(),Buffer.Length());
//Initialize ProgressBar
ProgressBar1->Max=Input->Count;
ProgressBar1->Position=0;
//parse each source line
for (int i=0;i<Input->Count;i++)
{
ParseLine(Output,Input->Strings[i]);
Output->Write("<br>\r\n",6);
ProgressBar1->Position++;
}
ProgressBar1->Position=0;
//Write html footer
AnsiString Footer="</div>\r\n</body>\r\n</html>";
Output->Write(Footer.c_str(),Footer.Length());
delete Input;
delete Output;
return true;
}
//---------------------------------------------------------------------------
AnsiString __fastcall TForm1::WriteHeader()
{
AnsiString Header="<html>\r\n<head>\r\n <title>";
//get title, if any
if(TitleEdit->Text=="")Header +="Untitled";
else Header += TitleEdit->Text;
Header+="</title>\r\n <meta http-equiv=\"content-type\" content=\"text/html;"
" charset=iso-8859-1\">\r\n"
" <meta name=\"author\" content=\"Michel Leunen (michel@leunen.com\">\r\n"
" <meta name=\"generator\" content=\"Src2Html V1.0\">\r\n"
" <style type=\"text/css\">\r\n <!--\r\n"
" .source {font-family: ";
//get font
Header +=Par->HtmlFont;
Header +=", Courier, mono; font-size: ";
//get size
Header +=SizeEdit->Text;
//get each parameter value corresponding to each token type
//we have to reverse the color value in order to have RGB
Header +="pt; margin-left: ";
Header +=MarginEdit->Text;
Header +="px; color: #000000}\r\n .comment {color: #";
Header +=ReverseHex(IntToHex(Par->Comment->Color,6));
if(Par->Comment->Bold)Header +="; font-weight: bold";
if(Par->Comment->Italic)Header +="; font-style: italic";
if(Par->Comment->Underline)Header +="; text-decoration: underline";
Header +="}\r\n .reserved {color : #";
Header +=ReverseHex(IntToHex(Par->ReservedWord->Color,6));
if(Par->ReservedWord->Bold)Header +="; font-weight: bold";
if(Par->ReservedWord->Italic)Header +="; font-style: italic";
if(Par->ReservedWord->Underline)Header +="; text-decoration: underline";
Header +="}\r\n .preprocessor {color : #";
Header +=ReverseHex(IntToHex(Par->Preprocessor->Color,6));
if(Par->Preprocessor->Bold)Header +="; font-weight: bold";
if(Par->Preprocessor->Italic)Header +="; font-style: italic";
if(Par->Preprocessor->Underline)Header +="; text-decoration: underline";
Header +="}\r\n .quotedstring {color : #";
Header +=ReverseHex(IntToHex(Par->QuotedString->Color,6));
if(Par->QuotedString->Bold)Header +="; font-weight: bold";
if(Par->QuotedString->Italic)Header +="; font-style: italic";
if(Par->QuotedString->Underline)Header +="; text-decoration: underline";
Header +="}\r\n -->\r\n";
Header +=" </style>\r\n</head>\r\n<body bgcolor=\"#FFFFFF\">\r\n"
"<center><h1>";
Header +=ExtractFileName(SourceEdit->Text);
Header +="</h1></center>\r\n<div class=\"source\"><p>\r\n";
return Header;
}
//---------------------------------------------------------------------------
AnsiString __fastcall TForm1::ReverseHex(AnsiString HexValue)
{
AnsiString ReverseString;
ReverseString.Insert(HexValue.SubString(1,2),1);
ReverseString.Insert(HexValue.SubString(3,2),1);
ReverseString.Insert(HexValue.SubString(5,2),1);
return ReverseString;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ParseLine(TFileStream *Out,AnsiString Line)
{
if(Line=="")return; //empty line
if (Comment==true) //there is a comment in a previous line
{
int Position=Line.Pos("*/"); //end of comment in the line?
if(Position!=0) //yep
{
//print beginning of line as comment
WriteComment(Out,Line.SubString(1,Position+1));
Comment=false;
//parse end of line
AnsiString NewLine=Line.SubString(Position+2,Line.Length());
ParseLine(Out,NewLine); //parse end of line
return;
}
else //no, whole line is a comment
{
WriteComment(Out,Line);
return;
}
}
if(Line[1]==' ') //blank character
{
Out->Write(" ",6);
if(Line.Length()>1) //if more characters in the line
{
//parse end of line
ParseLine(Out,Line.SubString(2,Line.Length()));
return;
}
//if blank = last character, parse next source line
else return;
}
if(Line[1]=='\t') //tab
{
for(int j=0;j<StrToInt(TabEdit->Text);j++)
{
Out->Write(" ",6); //replace tab with blank character
}
if(Line.Length()>1) //if more characters in the line
{
//parse end of line
ParseLine(Out,Line.SubString(2,Line.Length()));
return;
}
//if tab = last character, parse next source line
else return;
}
if(Line[1]=='#') //preprocessor directive
{
int Position=Line.Pos("//"); //comment in the line?
if(Position!=0) //yep
{
//write preprocessor directve until comment
WritePreprocessor(Out,Line.SubString(1,Position-1));
//parse end of line beginning at comment
AnsiString NewLine=Line.SubString(Position,Line.Length());
ParseLine(Out,NewLine);
return;
}
else //no "//" in the line
{
Position=Line.Pos("/*"); //comment in the line?
if(Position!=0) //yes
{
//write preprocessor directive until comment
WritePreprocessor(Out,Line.SubString(1,Position-1));
//parse end of line beginning at comment
AnsiString NewLine=Line.SubString(Position,Line.Length());
ParseLine(Out,NewLine);
return;
}
else //no comment in the line
{
//write whole line as preprocessor directive
WritePreprocessor(Out,Line);
return;
}
}
}
if(Line[1]=='/') //Comment?
{
if(Line.Length()>1) //more than 1 char on the line
{
if(Line[2]=='/') //comment "//"
{
WriteComment(Out,Line); //write whole line as comment
return;
}
if(Line[2]=='*') //comment "/*"
{
int Position=Line.Pos("*/");
//end of comment in the same line
if (Position!=0) //yes
{
//write comment until end of comment "*/"
WriteComment(Out,Line.SubString(1,Position+1));
//parse line beginning at end of comment
ParseLine(Out,Line.SubString(Position+2,Line.Length()));
return;
}
else //no end of comment "*/"
{ //in the line
Comment=true;
ParseLine(Out,Line);
return;
}
}
}
}
if(Line[1]=='"') //string
{
if(Line.Length()>1) //more than 1 char on the line
{
for(int i=2;i<Line.Length()+1;i++)
{
if(Line[i]=='"') //get string until '"'
{
if (Line[i-1]!='\\') //check if nested '"'
{
//write string
WriteQuotedString(Out,Line.SubString(1,i));
//parse end of line beginning after the ending '"'
if(i<Line.Length())ParseLine(Out,Line.SubString(i+1,Line.Length()));
return;
}
}
}
}
}
//here we already know that the beginning of line isn't a blank,
//an empty line, a preprocessor directive, a comment or a string
//it could be a reserved word or a 'normal' character
int i=1;
AnsiString RWord;
//get all alpha characters, if any. In that case, it could be either a
//reserved word or the name of a variable or function
while((IsAlpha(Line[i]))&&(i<Line.Length()))
{
RWord+=Line[i];
i++;
}
if(RWord!="") //it's not an alphanumerical character
{
if(IsReserved(RWord)) //Reserved word?
{
//write the reserved word
WriteReserved(Out,RWord);
//parse line after the reserved word
ParseLine(Out,Line.SubString(i,Line.Length()));
return;
}
else //it's not a reserved word
{
//write the word (variable name or function name)
Out->Write(RWord.c_str(),RWord.Length());
if(Line.Length()>1) //more than 1 char on the line
{
//parse line after the variable or function name
ParseLine(Out,Line.SubString(i,Line.Length()));
}
return;
}
}
else
{
//it's not a reserved word nor a variable or function name
//it's therefor a symbol like *./+=(){}[]...
RWord+=ReplaceLtAndGt(Line[1]);
Out->Write(RWord.c_str(),RWord.Length());
if(Line.Length()>1) //more than 1 char on the line
{
//if there is more characters in the line, parse the remainder
ParseLine(Out,Line.SubString(2,Line.Length()));
}
return;
}
}
//---------------------------------------------------------------------------
AnsiString __fastcall TForm1::ReplaceBlank(AnsiString Buffer)
{
AnsiString NewBuffer;
for (int i=1;i<Buffer.Length()+1;i++)
{
if(Buffer[i]==' ')NewBuffer.Insert(" ",NewBuffer.Length()+1);
else NewBuffer.Insert(Buffer[i],NewBuffer.Length()+1);
}
return NewBuffer;
}
//---------------------------------------------------------------------------
AnsiString __fastcall TForm1::ReplaceLtAndGt(AnsiString Buffer)
{
AnsiString NewBuffer;
for (int i=1;i<Buffer.Length()+1;i++)
{
if(Buffer[i]=='<')NewBuffer.Insert("<",NewBuffer.Length()+1);
else
{
if(Buffer[i]=='>')NewBuffer.Insert(">",NewBuffer.Length()+1);
else NewBuffer.Insert(Buffer[i],NewBuffer.Length()+1);
}
}
return NewBuffer;
}
//---------------------------------------------------------------------------
bool __fastcall TForm1::IsAlpha(char ch)
{
//all alphanumerical character plus _ (leading or ending)
const char Table[64]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_";
if(strchr(Table,ch))return true;
else return false;
}
//---------------------------------------------------------------------------
bool __fastcall TForm1::IsReserved(AnsiString Word)
{
for (int i=0;i<ReservedWordsComboBox->Items->Count;i++)
{
if(ReservedWordsComboBox->Items->Strings[i]==Word)return true;
}
return false;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WriteComment(TFileStream *Out,AnsiString Buffer)
{
AnsiString Temp="<span class=\"comment\">";
Temp+=ReplaceLtAndGt(ReplaceBlank(Buffer));
Temp+="</span>";
Out->Write(Temp.c_str(),Temp.Length());
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WritePreprocessor(TFileStream *Out,AnsiString Buffer)
{
AnsiString Temp="<span class=\"preprocessor\">";
Temp+=ReplaceLtAndGt(ReplaceBlank(Buffer));
Temp+="</span>";
Out->Write(Temp.c_str(),Temp.Length());
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WriteReserved(TFileStream *Out,AnsiString Buffer)
{
AnsiString Temp="<span class=\"reserved\">";
Temp+=Buffer;
Temp+="</span>";
Out->Write(Temp.c_str(),Temp.Length());
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WriteQuotedString(TFileStream *Out,AnsiString Buffer)
{
AnsiString Temp="<span class=\"quotedstring\">";
Temp+=ReplaceBlank(ReplaceLtAndGt(Buffer));
Temp+="</span>";
Out->Write(Temp.c_str(),Temp.Length());
}
//---------------------------------------------------------------------------