#!/usr/bin/perl
#
# (c) Copyright 2001-2007 The DirectFB Organization (directfb.org)
# (c) Copyright 2000-2004 Convergence (integrated media) GmbH
#
# All rights reserved.
#
# Written by Denis Oliver Kropp ,
# Andreas Hundt ,
# Sven Neumann ,
# Ville Syrjälä and
# Claudio Ciccani .
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
#
##################################
# TODO: CLEANUP CODE FURTHER !!!
##################################
#####################################################################################
# #
# Documentation generator written by Denis Oliver Kropp #
# #
# - Uses first argument as project name and second as version #
# - Reads header files from stdin, parsing is tied to the coding style #
# - Writes HTML 3.x to different files: 'index', 'types', , #
# #
# FIXME: remove all copy'n'waste code, cleanup more, simplify more, ... #
# #
#####################################################################################
$COLOR_BG = "#F8F4D8";
$COLOR_LINK = "#2369E0";
$COLOR_TEXT = "#232323";
$COLOR_TOP_BG = "#000000";
$COLOR_TOP_LINK = "#FFFFFF";
$COLOR_TITLE = "#CC7723";
$COLOR_TITLE_BG = "#203040";
$COLOR_TITLE_MAIN = "#DDDDDD";
$COLOR_ENTRIES_BG = "#F8F8F0";
$COLOR_ENTRIES_PTR = "#424242";
$COLOR_ENTRIES_ID = "#234269";
$COLOR_ENTRIES_DESC = "#303030";
$COLOR_ENUM_NAME = "#B04223";
$COLOR_ENUM_ENTRY_ID = "#429023";
$COLOR_ENUM_ENTRY_VAL = "#234269";
$COLOR_STRUCT_NAME = "#238423";
$COLOR_FUNCTYPE_NAME = "#D06923";
$COLOR_FUNCTYPE_HEAD = "#232342";
$COLOR_MACRO_NAME = "#2342A0";
$COLOR_MACRO_PARAMS = "#606080";
$COLOR_MACRO_VALUE = "#232342";
$COLOR_METHOD_HEAD = "#425469";
$COLOR_COPYRIGHT_BG = "#E0E8F0";
########################################################################################################################
## Top level just calls main function with args
#
$PROJECT = shift @ARGV;
$VERSION = shift @ARGV;
gen_doc( $PROJECT, $VERSION );
########################################################################################################################
########################################################################################################################
## Utilities
#
sub trim ($) {
local (*str) = @_;
# remove leading white space
$str =~ s/^\s*//g;
# remove trailing white space and new line
$str =~ s/\s*$//g;
}
sub print_list ($$) {
local (*list, $title) = @_;
print INDEX "\n",
"
\n",
" $title
\n",
" \n";
foreach $key (sort keys %list)
{
print INDEX " \n",
" $key\n",
" | \n",
" $list{$key}\n",
" |
\n";
}
print INDEX "
\n",
"
\n";
}
sub substitute_links ($) {
local (*str) = @_;
# Interface Methods
$str =~ s/(I\w+)\:\:(\w+)\(\)/\\1\:\:\2\(\)\<\/a\>/g;
# Automatic type links
$str =~ s/(\s)([A-Z][A-Z][A-Z][A-Z]?[a-z][a-z][a-z]?[\w0-9]+)/\1\\2\<\/a\>/g;
# Automatic type links
$str =~ s/(\s)($PROJECT[\w0-9]+)/\1\\2\<\/a\>/g;
# Explicit type links
$str =~ s/(\s)\@\_(\w[\w0-9]+)/\1\\2\<\/a\>/g;
}
sub type_link ($) {
my ($type) = @_;
trim( \$type );
if (defined($type_list{$type}))
{
return "$type";
}
elsif (defined($interfaces{$type}))
{
return "$type";
}
return "$type";
}
########################################################################################################################
## Generic parsers
#
sub parse_comment ($$$$) {
local (*head, *body, *options, $inithead) = @_;
local $headline_mode = 1;
local $list_open = 0;
if ($inithead ne "") {
$headline_mode = 0;
}
$head = $inithead;
$body = "";
%options = ();
while (<>)
{
chomp;
last if /^\s*\*+\/\s*$/;
s/^\s*[^\*\s]/\* /;
if ($headline_mode == 1)
{
if (/^\s*\*+\s*$/)
{
$headline_mode = 0;
}
elsif (/^\s*\*+\s*@(\w+)\s*=?\s*(.*)$/)
{
$options{$1} = $2;
}
elsif (/^\s*\*+\s*(.+)\*\/\s*$/)
{
$head .= " $1\n";
last;
}
elsif (/^\s*\*+\s*(.+)$/)
{
$head .= " $1\n";
}
}
else
{
if (/^\s*\*+\s*(.+)\*\/\s*$/)
{
$body .= " $1\n";
last;
}
elsif (/^\s*\*+\s*$/)
{
$body .= " \n";
}
elsif (/^\s*\*+\s\-\s(.+)$/)
{
if ($list_open == 0)
{
$list_open = 1;
$body .= "
- \n";
}
else
{
$body .= "
- \n";
}
$body .= " $1\n";
}
elsif (/^\s*\*+\s\s(.+)$/)
{
$body .= " $1\n";
}
elsif (/^\s*\*+\s(.+)$/)
{
if ($list_open == 1)
{
$list_open = 0;
$body .= "
\n";
}
$body .= " $1\n";
}
}
}
if ($list_open == 1)
{
$body .= " \n";
}
substitute_links (\$head);
substitute_links (\$body);
}
#
# Reads stdin until the end of the parameter list is reached.
# Returns list of parameter records.
#
# TODO: Add full comment support and use it for function types as well.
#
sub parse_params () {
local @entries;
while (<>)
{
chomp;
last if /^\s*\)\;\s*$/;
if ( /^\s*(const )?\s*([\w\ ]+)\s+(\**)(\w+,?)\s*$/ )
{
local $const = $1;
local $type = $2;
local $ptr = $3;
local $name = $4;
local $rec = {
TYPE => $const . type_link( $type ),
PTR => $ptr,
NAME => $name
};
push (@entries, $rec);
}
}
return @entries;
}
########################################################################################################################
## Type parsers
#
#
# Reads stdin until the end of the interface is reached.
# Writes formatted HTML to one file for the interface and one file per method.
# Parameter is the interface name.
#
sub parse_interface ($)
{
local ($interface) = @_;
local $section;
trim( \$interface );
html_create( INTERFACE, "$interface.html",
"" .
" $PROJECT Interfaces" .
"", $interface, $interface );
print INTERFACE "\n",
" $headline\n",
" $detailed\n",
"
";
print INTERFACE "\n",
"
\n";
print INTERFACE " \n";
print INTERFACE " Methods of $interface |
\n";
print INTERFACE " \n";
print INTERFACE " \n";
while (<>)
{
chomp;
last if /^\s*\)\s*$/;
if ( /^\s*\/\*\*\s*(.+)\s*\*\*\/\s*$/ )
{
$section = $1;
}
elsif ( /^\s*(\w+)\s*\(\s*\*\s*(\w+)\s*\)\s*\(?\s*$/ )
{
print INTERFACE " \n",
" $section\n",
" | \n",
" ",
" $2\n",
" | \n",
" $headline\n",
" |
\n";
html_create( FUNCTION, "${interface}_$2.html",
"" .
" $interface" .
"", $2, "$interface - $2" );
print FUNCTION "$headline
\n",
" \n",
" $1 $2 ( |
\n";
local @params = parse_params();
local $param;
for $param (@params)
{
print FUNCTION " \n",
" \n",
" | \n",
" $param->{TYPE}\n",
" | | \n",
" $param->{PTR}\n",
" | \n",
" $param->{NAME}\n",
" |
\n";
}
print FUNCTION " ); |
\n",
"
\n",
"\n";
print FUNCTION "$detailed
\n";
$headline = "";
$detailed = "";
$section = "";
html_close( FUNCTION );
}
elsif ( /^\s*\/\*\s*$/ )
{
parse_comment( \$headline, \$detailed, \$options, "" );
}
}
print INTERFACE " \n";
print INTERFACE "
\n",
"\n";
html_close( INTERFACE );
}
#
# Reads stdin until the end of the enum is reached.
# Writes formatted HTML to "types.html".
#
sub parse_enum
{
local %entries;
local @list;
local $pre;
while (<>)
{
chomp;
local $entry;
# entry with assignment (complete comment)
if ( /^\s*(\w+)\s*=\s*([\w\d\(\)\,\|\!\s]+[^\,\s])\s*,?\s*\/\*\s*(.+)\s*\*\/\s*$/ )
{
$entry = $1;
$values{ $entry } = $2;
$entries{ $entry } = $3;
}
# entry with assignment (opening comment)
elsif ( /^\s*(\w+)\s*=\s*([\w\d\(\)\,\|\!\s]+[^\,\s])\s*,?\s*\/\*\s*(.+)\s*$/ )
{
$entry = $1;
$values{ $entry } = $2;
parse_comment( \$t1, \$t2, \$opt, $3 );
$entries{ $entry } = $t1.$t2;
}
# entry with assignment (none or preceding comment)
elsif ( /^\s*(\w+)\s*=\s*([\w\d\(\)\,\|\!\s]+[^\,\s])\s*,?\s*$/ )
{
$entry = $1;
$values{ $entry } = $2;
$entries{ $entry } = $pre;
}
# entry without assignment (complete comment)
elsif ( /^\s*(\w+)\s*,?\s*\/\*\s*(.+)\s*\*\/\s*$/ )
{
$entry = $1;
$entries{ $entry } = $2;
}
# entry without assignment (opening comment)
elsif ( /^\s*(\w+)\s*,?\s*\/\*\s*(.+)\s*$/ )
{
$entry = $1;
parse_comment( \$t1, \$t2, \$opt, $2 );
$entries{ $entry } = $t1.$t2;
}
# entry without assignment (none or preceding comment)
elsif ( /^\s*(\w+)\s*,?\s*$/ )
{
$entry = $1;
$entries{ $entry } = $pre;
}
# preceding comment (complete)
elsif ( /^\s*\/\*\s*(.+)\s*\*\/\s*$/ )
{
$pre = $1;
}
# preceding comment (opening)
elsif ( /^\s*\/\*\s*(.+)\s*$/ )
{
parse_comment( \$t1, \$t2, \$opt, $1 );
$pre = $t1.$t2;
}
# end of enum
elsif ( /^\s*\}\s*(\w+)\s*\;\s*$/ )
{
$enum = $1;
trim( \$enum );
$enum_list{$enum} = $headline;
$type_list{$enum} = $headline;
last;
}
# blank line?
else
{
$pre = "";
}
if ($entry ne "")
{
push (@list, $entry);
}
}
if (scalar @list > 0)
{
print TYPES "\n",
" \n",
" $enum
\n",
" \n",
"
$headline
\n",
" \n";
foreach $key (@list)
{
substitute_links (\$entries{$key});
print TYPES " | \n",
" $key\n",
" | | \n",
" $values{$key}\n",
" | | \n",
" $entries{$key}\n",
" |
\n";
}
print TYPES "
\n",
"\n",
" $detailed\n",
"
\n";
}
}
#
# Reads stdin until the end of the enum is reached.
# Writes formatted HTML to "types.html".
#
sub parse_struct
{
local @entries;
local %entries_params;
local %entries_types;
local %entries_ptrs;
while (<>)
{
chomp;
local $entry;
# without comment
if ( /^\s*(const )?\s*([\w ]+)\s+(\**)([\w\d\+\[\]]+)(\s*:\s*\d+)?;\s*$/ )
{
$const = $1;
$type = $2;
$ptr = $3;
$entry = $4.$5;
$text = "";
}
# complete one line entry
elsif ( /^\s*(const )?\s*([\w ]+)\s+(\**)([\w\d\+\[\]]+)(\s*:\s*\d+)?;\s*\/\*\s*(.+)\*\/\s*$/ )
{
$const = $1;
$type = $2;
$ptr = $3;
$entry = $4.$5;
$text = $6;
}
# with comment opening
elsif ( /^\s*(const )?\s*([\w ]+)\s+(\**)([\w\d\+\[\]]+)(\s*:\s*\d+)?;\s*\/\*\s*(.+)\s*$/ )
{
$const = $1;
$type = $2;
$ptr = $3;
$entry = $4.$5;
parse_comment( \$t1, \$t2, \$opt, $6 );
$text = $t1.$t2;
}
elsif ( /^\s*\}\s*(\w+)\s*\;\s*$/ )
{
$struct = $1;
trim( \$struct );
$struct_list{$struct} = $headline;
$type_list{$struct} = $headline;
last;
}
if ($entry ne "")
{
# TODO: Use structure
$entries_types{$entry} = $const . type_link( $type );
$entries_ptrs{$entry} = $ptr;
$entries_params{$entry} = $text;
push (@entries, $entry);
}
}
if (scalar @entries > 0)
{
print TYPES "",
" \n",
" $struct
\n",
" \n",
"
$headline
\n",
" \n";
foreach $key (@entries)
{
substitute_links (\$entries_params{$key});
print TYPES " | \n",
" $entries_types{$key}\n",
" | | \n",
" $entries_ptrs{$key}\n",
" | \n",
" $key\n",
" | | \n",
" $entries_params{$key}\n",
" |
\n";
}
print TYPES "
\n",
"\n",
" $detailed\n",
"
\n";
}
}
#
# Reads stdin until the end of the function type is reached.
# Writes formatted HTML to "types.html".
# Parameters are the return type and function type name.
#
sub parse_func ($$)
{
local ($rtype, $name) = @_;
local @entries;
local %entries_params;
local %entries_types;
local %entries_ptrs;
trim( \$rtype );
trim( \$name );
while (<>)
{
chomp;
local $entry;
# without comment
if ( /^\s*(const )?\s*([\w ]+)\s+(\**)([\w\d\+\[\]]+)(\s*:\s*\d+)?,?\s*$/ )
{
$const = $1;
$type = $2;
$ptr = $3;
$entry = $4.$5;
$text = "";
}
# complete one line entry
elsif ( /^\s*(const )?\s*([\w ]+)\s+(\**)([\w\d\+\[\]]+)(\s*:\s*\d+)?,?\s*\/\*\s*(.+)\*\/\s*$/ )
{
$const = $1;
$type = $2;
$ptr = $3;
$entry = $4.$5;
$text = $6;
}
# with comment opening
elsif ( /^\s*(const )?\s*([\w ]+)\s+(\**)([\w\d\+\[\]]+)(\s*:\s*\d+)?,?\s*\/\*\s*(.+)\s*$/ )
{
$const = $1;
$type = $2;
$ptr = $3;
$entry = $4.$5;
parse_comment( \$t1, \$t2, \$opt, $6 );
$text = $t1.$t2;
}
elsif ( /^\s*\)\;\s*$/ )
{
$func_list{$name} = $headline;
$type_list{$name} = $headline;
last;
}
if ($entry ne "")
{
# TODO: Use structure
$entries_types{$entry} = $const . type_link( $type );
$entries_ptrs{$entry} = $ptr;
$entries_params{$entry} = $text;
push (@entries, $entry);
}
}
$rtype = type_link( $rtype );
if (scalar @entries > 0)
{
print TYPES "",
" \n",
" $name
\n",
" \n",
"
$headline
\n",
" \n",
" \n",
" $rtype (*$name) (\n",
" |
\n";
foreach $key (@entries)
{
print TYPES " \n",
" \n",
" | \n",
" $entries_types{$key}\n",
" | | \n",
" $entries_ptrs{$key}\n",
" | \n",
" $key\n",
" | | \n",
" $entries_params{$key}\n",
" |
\n";
}
print TYPES " ); |
\n",
"
\n",
"\n",
" $detailed\n",
"
\n";
}
}
#
# Reads stdin until the end of the macro is reached.
# Writes formatted HTML to "types.html".
# Parameters are the macro name, parameters and value.
#
sub parse_macro ($$$)
{
local ($macro, $params, $value) = @_;
trim( \$macro );
trim( \$params );
trim( \$value );
while (<>)
{
chomp;
last unless /\\$/;
}
if (!defined ($options{"internal"}) && $value ne "") {
$macro_list{$macro} = $headline;
$type_list{$macro} = $headline;
$value =~ s/^\s*\\\s*$//;
print TYPES "\n",
" \n",
" \n",
" $macro\n",
" $params\n",
"
\n",
" \n",
"
$headline
\n",
" $value\n",
"\n",
" $detailed\n",
"
\n";
}
}
########################################################################################################################
## HTML Files
#
sub html_create ($$$$$)
{
local ($FILE, $filename, $title, $subtitle, $singletitle) = @_;
open( $FILE, ">$filename" )
or die ("*** Can not open '$filename' for writing:\n*** $!");
print $FILE "\n",
"\n",
"\n",
"\n",
" $singletitle [$PROJECT Reference Manual]\n",
"\n",
"\n",
"\n",
"\n",
" \n",
" \n",
" | \n",
" ",
" Reference Manual - $VERSION\n",
" |
\n",
" \n";
if ($subtitle)
{
print $FILE " \n",
" \n",
" $title \n",
" | \n",
" $subtitle\n",
" | \n",
" \n";
}
else
{
print $FILE " $title\n";
}
print $FILE " |
\n",
"
\n",
"\n";
}
sub html_close ($)
{
local ($FILE) = @_;
print $FILE "\n",
"\n",
" \n",
" ",
" ",
" ",
" | \n",
" This work is licensed under a",
" ",
" Creative Commons Attribution-Share Alike 3.0 License",
" |
\n",
"
\n",
"\n",
"\n";
close( $FILE );
}
########################################################################################################################
## Main Function
#
sub gen_doc ($$) {
local ($project, $version) = @_;
trim( \$project );
trim( \$version );
html_create( INDEX, "index.html", "Index Page", "", "Index" );
html_create( TYPES, "types.html", "$PROJECT Types", "", "Types" );
print INDEX "\n",
"
\n",
" Interfaces
\n",
" \n";
while (<>) {
chomp;
if ( /^\s*DECLARE_INTERFACE\s*\(\s*(\w+)\s\)\s*$/ ) {
$interfaces{$1} = "$headline $detailed";
print INDEX " \n",
" $1\n",
" | \n",
" $headline $detailed\n",
" |
\n";
}
elsif ( /^\s*DEFINE_INTERFACE\s*\(\s*(\w+),\s*$/ ) {
parse_interface( $1 );
}
elsif ( /^\s*typedef\s+enum\s*\{?\s*$/ ) {
parse_enum();
}
elsif ( /^\s*typedef\s+(struct|union)\s*\{?\s*$/ ) {
parse_struct();
}
elsif ( /^\s*typedef\s+(\w+)\s+\(\*(\w+)\)\s*\(\s*$/ ) {
parse_func( $1, $2 );
}
elsif ( /^\s*#define\s+([^\(\s]+)(\([^\)]*\))?\s*(.*)/ ) {
parse_macro( $1, $2, $3 );
}
elsif ( /^\s*\/\*\s*$/ ) {
parse_comment( \$headline, \$detailed, \$options, "" );
}
else {
$headline = "";
$detailed = "";
%options = ();
}
}
print INDEX "
\n",
"\n";
print_list( \%func_list, "Function Types" );
print_list( \%enum_list, "Enumerated Types" );
print_list( \%struct_list, "Structured Types" );
print_list( \%macro_list, "Definitions" );
html_close( INDEX );
html_close( TYPES );
}