#
# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved.
# This component and the accompanying materials are made available
# under the terms of "Eclipse Public License v1.0"
# which accompanies this distribution, and is available
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
#
# Initial Contributors:
# Nokia Corporation - initial contribution.
#
# Contributors:
#
# Description:
#
#!/usr/local/bin/perl
#
# doxy.pl
#
# THis script generates doxygen formatted documentation from source code
#
# ***********************************************************************
#
# Change history:
#
# 13.06.2005 This could be v.1.0
#
#
#
# ***********************************************************************
use strict;
use Tk;
use Tk::NoteBook;
use Tk::DirTree;
use Tk::DialogBox;
use Cwd;
use File::Copy;
my ($TOP_GIF);
$TOP_GIF='top.gif';
#
# finds doc-dirs where is Mainpage.dox
#
sub find_doc {
my ($rdir_list, $cf, $path, $last_dir, $dir);
$rdir_list = shift;
$cf = shift;
$path = cwd();
$last_dir=$path;
$last_dir=~s/.*\///;
if ($last_dir=~m/^$$cf{'document_dir'}$/) {
$path=~s/\/$$cf{'document_dir'}.*//;
if (-s $$cf{'mainpage'}) {
push(@$rdir_list, $path);
}
}
foreach $dir (<*>) {
if (-d $dir) {
chdir $dir;
&find_doc($rdir_list, $cf);
chdir "..";
}
}
}
#
# rips class hierarchy from hierarchy.html
#
sub rip_hierarchy {
my ($rlines, $line, $l_count, $page);
$rlines = shift;
$page = shift;
$l_count = 0;
open (HIERARCHY, $page);
while ($line = <HIERARCHY>) {
chomp($line);
if ($line=~m/\<\/ul\>/) {
if ($l_count==1) {
push (@$rlines, $line."\n");
}
$l_count--;
}
if ($line=~m/\<ul\>/) {
$l_count++;
}
if ($l_count > 0) {
$line=~s/\<h1\>.*\<\/h1\>//;
push (@$rlines, $line."\n");
}
#if ($line=~m/\<h1\>.*\<ul\>/) {
# $line=~s/\<h1\>.*\<\/h1\>//;
# push (@$rlines, $line."\n");
# $l_count++;
#}
}
close (HIERARCHY);
}
#
# rips class hierarchy from annotated.html
#
sub rip_annotated {
my ($rlines, $line, $page);
$rlines = shift;
$page = shift;
open (ANNOTATED, $page);
#$line = "<h1>Class Hierarchy</h1>This inheritance list is sorted roughly, but not completely, alphabetically:<ul>\n";
$line = "This inheritance list is sorted roughly, but not completely, alphabetically:<ul>\n";
push (@$rlines, $line);
while ($line = <ANNOTATED>) {
chomp($line);
if ($line=~m/.*<tr.*indexkey.*indexvalue.*tr>/) {
$line=~s/^.*<tr>.*<a//;
$line=~s/<\/td>.*$//;
$line=~s/^/<li><a/;
push (@$rlines, $line."\n");
}
}
close (ANNOTATED);
}
#
# finds right place from Mainpage.dox and inserts
# ripped lines
#
sub find_replace {
my ($rlines, $infile, $tmpfile, $cf);
$rlines = shift;
$cf = shift;
$infile = $$cf{'document_dir'}.'/'.$$cf{'mainpage'};
$tmpfile = $infile.'.tmp';
open (IN_F, $infile) or die "Cannot open input file $infile : $!";
open (TMP_F, "> $tmpfile") or die "Cannot open tmp file $tmpfile : $!";
while (<IN_F>) {
unless ((/\s*\<h1\>.*\<ul\>/) ||
(/\s*\<li\>/) ||
(/\s*\<ul\>/) ||
(/\s*\<\/ul\>/) ||
(/\s*\*\//))
{
print TMP_F $_;
}
}
print TMP_F @$rlines;
print TMP_F ' */';
close (IN_F);
close (TMP_F);
unlink $infile or die "Cannot unlink file : $!";
rename $tmpfile, $infile or die "Cannot rename file : $!";
}
#
# Decides from what file class hierarchy should be taken
# routes hierarchy lines to replace-function
#
sub update_mainpage {
my ($cf, @lines, $hierarchy, $annotated);
$cf = shift;
@lines = ();
$hierarchy = $$cf{'document_dir'}.'/hierarchy.html';
$annotated = $$cf{'document_dir'}.'/annotated.html';
if (-s $hierarchy) {
&rip_hierarchy(\@lines, $hierarchy);
}
elsif (-s $annotated) {
&rip_annotated(\@lines, $annotated);
}
if (-s $$cf{'document_dir'}.'/'.$$cf{'mainpage'}) {
&find_replace(\@lines, $cf);
}
}
#
# runs doxygen in each dir from where Mainpage.dox is found
# updates class hierarchy in Mainpage.dox
#
sub do_doxy {
my ($dir, $list, $cf, $doxy_com, $path);
$list = shift;
$cf = shift;
$path = shift() .'/'."$TOP_GIF";
$doxy_com = $$cf{'doxy_command'}.' '.$$cf{'doxyfile'};
foreach $dir (@$list) {
chdir $dir;
copy($path, $$cf{'document_dir'}.'/');
system($doxy_com) == 0
or die "Cannot execute command $doxy_com : $?";
# &update_mainpage($cf);
# system($doxy_com) == 0
# or die "Cannot execute command $doxy_com : $?";
}
}
#
# checks that configuration file item exist and is defined
#
sub check_conf_item {
my $cf = shift;
my $prop = shift;
die "$prop not found from configuration file." if !exists $$cf{$prop};
die "$prop not defined in configuration file." if !defined $$cf{$prop};
}
#
# checks configuration file items
#
sub check_configuration {
my $cf = shift;
check_conf_item ($cf, 'mainpage');
check_conf_item ($cf, 'document_dir');
check_conf_item ($cf, 'doxyfile');
check_conf_item ($cf, 'doxy_command');
check_conf_item ($cf, 'root_path');
check_conf_item ($cf, 'footer');
check_conf_item ($cf, 'header');
check_conf_item ($cf, 'stylesheet');
}
#
# loads configuration file and validates it
#
sub conf {
my $cf = shift;
my $c_file = shift;
open (CONFF, $c_file) or die "Cannot open configuration file : $!";
while (<CONFF>) {
chomp;
s/#.*//;
s/^\s+//;
s/\s+$//;
next unless length;
my ($var, $value) = split (/\s*=\s*/, $_, 2);
$$cf{$var} = $value;
}
close(CONFF);
check_configuration($cf);
}
#
# GUI : opens file browse window
#
sub gui_browse_file {
my $mp = shift;
my $top = shift;
my $ext = shift;
my $typelabel = shift;
my $type = shift;
my $initialfile = shift;
my $title = shift;
my $fi;
$fi = $$top->getOpenFile( -defaultextension => "$ext",
-filetypes =>
[["$typelabel", "$type"],
['All files', '*']
],
-initialdir => Cwd::cwd(),
-initialfile => "$initialfile",
-title => "$title"
);
$fi=~s/^.*\///;
$$mp = $fi;
}
#
# GUI : opens directory tree browser
#
sub gui_browse_root_path {
my $mp = shift;
my $top = shift;
my $fi = 0;
my $dir = Cwd::cwd();
my $popup = $$top->Toplevel(-title=>'Browse');
$popup->Scrolled('DirTree',
-scrollbars => 'osoe',
-width => 50,
-height => 30,
-selectmode => 'browse',
-exportselection => 1,
-browsecmd => sub{$dir=shift;},
-command => sub{$fi=1;}
)->pack(-fill => "both", -expand => 1);
$popup->waitVariable(\$fi);
if ($fi==1) {
$dir=~s/\//\\/g;
$$mp = $dir;
}
$popup->destroy();
}
#
# GUI : Returns constant text when pressing doxycommand default button
#
sub gui_browse_doxycommand {
my $mp = shift;
my $top = shift;
$$mp = "doxygen";
}
#
# GUI : Returns constant text when pressing docdir default button
#
sub gui_browse_docdir {
my $mp = shift;
my $top = shift;
$$mp = "doc";
}
#
# GUI : Opens configuration file browse window
#
sub gui_browse_open_conf {
my $cf = shift;
my $top = shift;
my $bk = shift;
my $fi;
$fi = $$top->getOpenFile( -defaultextension => ".conf",
-filetypes =>
[['Doxy configurationfile', '.conf'],
['All files', '*']
],
-initialdir => Cwd::cwd(),
-initialfile => '',
-title => 'Select doxy.pl configuration file'
);
&conf($cf, $fi);
$fi=~s/^.*\///;
$$bk->pageconfigure("tab1", -label => $fi);
}
#
# GUI : saves configuration file
#
sub gui_save_conf {
my $cf = shift;
my $file = shift;
my $key;
open (SAVE_FILE, "> $file")
or die "Cannot open file $file to save : $!";
foreach $key (keys %$cf) {
print SAVE_FILE "$key=$$cf{$key}\n";
}
close (SAVE_FILE);
}
#
# GUI : opens file save dialog for configuration file
#
sub gui_browse_save_conf {
my $cf = shift;
my $top = shift;
my $bk = shift;
my $fi;
my $le = $$bk->pagecget("tab1", -label);
$fi = $$top->getSaveFile( -defaultextension => ".conf",
-filetypes =>
[['Doxy configuration', '.conf'],
['All files', '*']
],
-initialdir => Cwd::cwd(),
-initialfile => $le,
-title => 'Save doxy configuration file'
);
&gui_save_conf($cf, $fi);
$fi=~s/^.*\///;
$$bk->pageconfigure("tab1", -label => $fi);
}
#
# GUI : creates menu resource
#
sub gui_create_menu {
my $top = shift;
my $cf = shift;
my $bk = shift;
my $menu =
[
[Cascade => "~File", -tearoff => 0, -menuitems =>
[
[Button => "~Open", -command => [\&gui_browse_open_conf, \%$cf, \$$top, \$$bk]],
[Button => "~Save", -command => [\&gui_browse_save_conf, \%$cf, \$$top, \$$bk]],
[Button => "~Quit", -command => sub{exit();}],
]
],
];
my $menub = $$top->Menu(-menuitems => $menu);
$$top->configure(-menu => $menub);
}
#
# GUI : handles what happens when pressing run button
#
sub gui_run {
my $cf = shift;
&check_configuration($cf);
&update_doxyfile($cf);
my (@dir_list, $path);
$path = cwd();
chdir $$cf{root_path};
&find_doc(\@dir_list, $cf);
&do_doxy(\@dir_list, $cf, $path);
chdir $path;
}
#
# GUI : creates dialog inside tab folder
#
sub gui_create_tab {
my $book = shift;
my $top = shift;
my $configuration = shift;
my $tab = shift;
my $label = shift;
my $conf_tab;
$conf_tab = $$book->add( $tab, -label=>$label );
my $frame = $conf_tab->Frame()->pack(-anchor=>'n');
$frame->Label(-text=>'')->grid(-column=>0,-row=>0,-sticky=>'ew');
$frame->Label(-text=>'')->grid(-column=>1,-row=>0,-sticky=>'ew');
$frame->Label(-text=>'')->grid(-column=>2,-row=>0,-sticky=>'ew');
$frame->Label(-text=>'Mainpage:',-anchor=>'w')->grid(-column=>0,-row=>1,-sticky=>'ew');
$frame->Entry(-textvariable=>\$$configuration{mainpage})->grid(-column=>1,-row=>1,-sticky=>'ew');
$frame->Button( -text => "Browse",
-command => [\&gui_browse_file, \$$configuration{mainpage}, \$$top, '.dox','Doxygen mainpage', '.dox', 'Mainpage.dox', 'Select mainpage filename'],
-width => 5)->
grid(-column=>2,-row=>1,-sticky=>'ew', -padx=>5, -pady=>5);
$frame->Label(-text=>'Doxyfile:',-anchor=>'w')->grid(-column=>0,-row=>2,-sticky=>'ew');
$frame->Entry(-textvariable=>\$$configuration{doxyfile})->grid(-column=>1,-row=>2,-sticky=>'ew');
$frame->Button( -text => "Browse",
-command => [\&gui_browse_file, \$$configuration{doxyfile}, \$$top,'','Doxygen configurationfile','Doxyfile','Doxyfile', 'Select doxygen configuration filename'],
-width => 5)->
grid(-column=>2,-row=>2,-sticky=>'ew', -padx=>5, -pady=>5);
$frame->Label(-text=>'Doxy command:',-anchor=>'w')->grid(-column=>0,-row=>3,-sticky=>'ew');
$frame->Entry(-textvariable=>\$$configuration{doxy_command})->grid(-column=>1,-row=>3,-sticky=>'ew');
$frame->Button( -text => "Default",
-command => [\&gui_browse_doxycommand, \$$configuration{doxy_command}, \$$top],
-width => 5)->
grid(-column=>2,-row=>3,-sticky=>'ew', -padx=>5, -pady=>5);
$frame->Label(-text=>'Document dir:',-anchor=>'w')->grid(-column=>0,-row=>4,-sticky=>'ew');
$frame->Entry(-textvariable=>\$$configuration{document_dir})->grid(-column=>1,-row=>4,-sticky=>'ew');
$frame->Button( -text => "Default",
-command => [\&gui_browse_docdir, \$$configuration{document_dir}, \$$top],
-width => 5)->
grid(-column=>2,-row=>4,-sticky=>'ew', -padx=>5, -pady=>5);
$frame->Label(-text=>'Header file:',-anchor=>'w')->grid(-column=>0,-row=>5,-sticky=>'ew');
$frame->Entry(-textvariable=>\$$configuration{header})->grid(-column=>1,-row=>5,-sticky=>'ew');
$frame->Button( -text => "Browse",
-command => [\&gui_browse_file, \$$configuration{header}, \$$top, '.html', 'Header file', '.html', 'header.html', 'Select header filename'],
-width => 5)->
grid(-column=>2,-row=>5,-sticky=>'ew', -padx=>5, -pady=>5);
$frame->Label(-text=>'Footer file:',-anchor=>'w')->grid(-column=>0,-row=>6,-sticky=>'ew');
$frame->Entry(-textvariable=>\$$configuration{footer})->grid(-column=>1,-row=>6,-sticky=>'ew');
$frame->Button( -text => "Browse",
-command => [\&gui_browse_file, \$$configuration{footer}, \$$top, '.html', 'Footer file', '.html', 'footer.html', 'Select footer filename'],
-width => 5)->
grid(-column=>2,-row=>6,-sticky=>'ew', -padx=>5, -pady=>5);
$frame->Label(-text=>'Stylesheet:',-anchor=>'w')->grid(-column=>0,-row=>7,-sticky=>'ew');
$frame->Entry(-textvariable=>\$$configuration{stylesheet})->grid(-column=>1,-row=>7,-sticky=>'ew');
$frame->Button( -text => "Browse",
-command => [\&gui_browse_file, \$$configuration{stylesheet}, \$$top,'.css','Stylesheet', '.css', 'stylesheet.css','Select stylesheet filename'],
-width => 5)->
grid(-column=>2,-row=>7,-sticky=>'ew', -padx=>5, -pady=>5);
$frame->Label(-text=>'Root path:',-anchor=>'w')->grid(-column=>0,-row=>8,-sticky=>'ew');
$frame->Entry(-textvariable=>\$$configuration{root_path})->grid(-column=>1,-row=>8,-sticky=>'ew');
$frame->Button( -text => "Browse",
-command => [\&gui_browse_root_path, \$$configuration{root_path}, \$$top],
-width => 5)->
grid(-column=>2,-row=>8,-sticky=>'ew', -padx=>5, -pady=>5);
$frame->Button( -text => "Run",
-command => [\&gui_run, \%$configuration],
-width => 5)->
grid(-column=>1,-row=>9,-sticky=>'ew', -padx=>5, -pady=>5);
}
#
# GUI : Creates GUI
#
sub gui {
my ($mw, @dir_list, $book, $tab);
my (%configuration);
$mw = new MainWindow;
$mw->geometry( "450x400" );
&gui_create_menu(\$mw, \%configuration, \$book);
$book = $mw->NoteBook()->pack( -fill=>'both', -expand=>1 );
&gui_create_tab(\$book, \$mw, \%configuration, "tab1", "Configuration");
MainLoop;
}
#
# Updates property in doxygen configuration file
#
sub update_doxyfile_item {
my $fi = shift;
my $file = shift;
my $doxfile = shift;
my $find = "($fi)(\\s*)(=)(\\s*)(.*)";
$file=~s/\\/\\\\/g;
my $replace = "\\1\\2\\3\\4$file";
system ("perl -p -i.ftr -e \"s/$find/$replace/\" $doxfile") == 0
or die "Cannot update $fi to $doxfile : $?";
}
#
# List of properties to update in doxygen configuration
#
sub update_doxyfile {
my $cf = shift;
update_doxyfile_item("HTML_HEADER", $$cf{header}, $$cf{doxyfile});
update_doxyfile_item("HTML_FOOTER", $$cf{footer}, $$cf{doxyfile});
update_doxyfile_item("HTML_STYLESHEET", $$cf{stylesheet}, $$cf{doxyfile});
update_doxyfile_item("HTML_OUTPUT", $$cf{document_dir}, $$cf{doxyfile});
#update_doxyfile_item("INCLUDE_PATH", $$cf{include_path}, $$cf{doxyfile});
}
#
# commandline mode
#
sub batch {
my ($c_file) = shift;
if (-s $c_file) {
my (%conf);
&conf(\%conf, $c_file);
&update_doxyfile(\%conf);
my (@dir_list, $path);
$path = cwd();
chdir $conf{root_path};
&find_doc(\@dir_list, \%conf);
&do_doxy(\@dir_list, \%conf, $path);
chdir $path;
}
else {
die "Configuration file \"$c_file\" not found : $!";
}
}
#
# Main program :
#
# if no arguments -> run gui
#
if (0 == scalar(@ARGV)) {
gui();
exit();
}
#
# with arguments -> run cmdline version
#
batch(@ARGV[0]);