#!/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 = "#C0B090"; $COLOR_TOP_LINK = "#203040"; $COLOR_TITLE = "#E09040"; $COLOR_TITLE_BG = "#284460"; $COLOR_TITLE_MAIN = "#D0D0D0"; $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"; } print INDEX "
\n", " $key\n", " \n", " $list{$key}\n", "
\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; $head = "\n"; $body = "\n"; if ($inithead ne "") { $headline_mode = 0; $head .= " $inithead\n"; } %options = (); while (<>) { chomp; last if /^\s*\*+\/\s*$/; # Prepend asterisk if first non-whitespace isn't an asterisk s/^\s*([^\*\s])/\* $1/; # In head line mode append to $head 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 # Otherwise append to $body { 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 ); if (!defined ($interfaces{$interface})) { print "WARNING: Interface definition '$interface' has no declaration!\n" } 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 " \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"; html_create( FUNCTION, "${interface}_$2.html", "" . " $interface" . "", $2, "$interface - $2" ); print FUNCTION "

$headline

\n", "
Methods of $interface
\n", " $section\n", " \n", " ", " $2\n", " \n", " $headline\n", "
\n", " \n"; local @params = parse_params(); local $param; for $param (@params) { print FUNCTION " \n"; } print FUNCTION " \n", "
$1 $2 (
\n", "  \n", " \n", " $param->{TYPE}\n", "  \n", " $param->{PTR}\n", " \n", " $param->{NAME}\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"; } print TYPES "
 \n", " $key\n", "  \n", " $values{$key}\n", "  \n", " $entries{$key}\n", "
\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"; } print TYPES "
 \n", " $entries_types{$key}\n", "  \n", " $entries_ptrs{$key}\n", " \n", " $key\n", "  \n", " $entries_params{$key}\n", "
\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"; foreach $key (@entries) { print TYPES " \n"; } print TYPES " \n", "
\n", " $rtype (*$name) (\n", "
\n", "  \n", " \n", " $entries_types{$key}\n", "  \n", " $entries_ptrs{$key}\n", " \n", " $key\n", "  \n", " $entries_params{$key}\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", " \n", " \n", "   ", " Reference Manual - $VERSION\n", "
\n"; if ($subtitle) { print $FILE " \n", " \n", "
\n", " $title \n", " \n", "  $subtitle\n", "
\n"; } else { print $FILE " $title\n"; } print $FILE "
\n", "\n"; } sub html_close ($) { local ($FILE) = @_; print $FILE "\n", "\n", " \n", "
\n", " ", " \"Creative", " ", " \n", " This work is licensed under a", " ", " Creative Commons Attribution-Share Alike 3.0 License", "
\n", "\n", "\n"; close( $FILE ); } ######################################################################################################################## ## Main Function # sub gen_doc ($$) { local ($project, $version) = @_; trim( \$project ); trim( \$version ); html_create( INDEX, "index.html", "$PROJECT Reference", "API Overview", "Index" ); html_create( TYPES, "types.html", "$PROJECT Reference", "Type Definitions", "Types" ); print INDEX "

\n", "

\n", "

Interfaces

\n", " \n"; while (<>) { chomp; if ( /^\s*DECLARE_INTERFACE\s*\(\s*(\w+)\s\)\s*$/ ) { $interface = $1; trim( \$interface ); if (!defined ($interfaces{$interface})) { print INDEX " \n"; $interfaces{$interface} = "$headline $detailed"; } } 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", " $1\n", " \n", " $headline $detailed\n", "
\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 ); }