#!/usr/bin/perl -w
#
# Format ImageMagick comments into POD-format or HTML format
# documentation
# Produces *.pod or *.html files corresponding to *.c files
#
# Written by Bob Friesenhahn, April 1997
#
$opt_format='html';
$opt_srcdir='';
$opt_outdir='';
use Getopt::Long;
if ( ! GetOptions(
'format=s' => \$opt_format,
'srcdir=s' => \$opt_srcdir,
'outdir=s' => \$opt_outdir,
)
) {
print("Usage: fmtdocs [-srcdir srcdir] [-outdir outdir] [-format format] \n");
exit(1);
}
#
# Source files to use
#
@srcs = ('animate.c',
'annotate.c',
'attribute.c',
'blob.c',
'cache.c',
'cache-view.c',
'color.c',
'colorspace.c',
'compare.c',
'composite.c',
'constitute.c',
'decorate.c',
'deprecate.c',
'draw.c',
'drawing-wand.c',
'display.c',
'effect.c',
'enhance.c',
'exception.c',
'fx.c',
'image.c',
'list.c',
'magick.c',
'magick-wand.c',
'memory.c',
'monitor.c',
'montage.c',
'paint.c',
'pixel-iterator.c',
'pixel-wand.c',
'profile.c',
'quantize.c',
'registry.c',
'resource.c',
'segment.c',
'shear.c',
'signature.c',
'stream.c',
'transform.c',
'resize.c',
'version.c');
$tmpname_pre_format = "/tmp/fmtdocs_pre.$$";
$tmpname_pod = "/tmp/fmtdocs_pod.$$";
$tmpname_html = "/tmp/fmtdocs_html.$$";
#@srcs = ('draw.c');
#
# What is for source files
#
%whatis =
(
'animate', 'Interactively Animate an Image Sequence',
'annotate', 'Annotate an Image',
'attribute', 'Set Text Attributes',
'blob', 'Read or Write Binary Large OBjects',
'color', 'Count the Colors in an Image',
'colorspace', 'Dealing with Image Colorspaces',
'compare', 'Compare an Image to a Reconstructed Image',
'constitute', 'Constitute an Image',
'composite', 'Composite an Image',
'decorate', 'Decorate an Image',
'deprecate', 'Deprecated Methods',
'display', 'Interactively Display and Edit an Image',
'draw', 'Draw on an Image',
'drawing_wand', 'Image Vector Drawing',
'effect', 'Add an Effect',
'fx', 'Add a Special Effect',
'enhance', 'Enhance an Image',
'exception', 'Dealing with Exceptions',
'image', 'Image Methods',
'list', 'Working with Image Lists',
'cache', 'Get or Set Image Pixels',
'cache_view', 'Working with Cache Views',
'magick', 'Read or List Image formats',
'magick_wand', 'Magick Wand',
'memory', 'Memory Allocation',
'monitor', 'Monitor the Progress of an Image Operation',
'montage', 'Create an Image Thumbnail',
'paint', 'Paint on an Image',
'pixel_iterator', 'Pixel Iterator',
'pixel_wand', 'Pixel Wand',
'profile', 'Dealing with Image Profiles',
'quantize', 'Reduce the Number of Unique Colors in an Image',
'registry', 'The Registry',
'resource', 'Minitor or Limit Resource Consumption',
'segment', 'Segment an Image with Thresholding Fuzzy c-Means',
'shear', 'Shear or Rotate an Image by an Arbitrary Angle',
'signature', 'Compute a Digital Signature for an Image',
'stream', 'The Pixel FIFO',
'transform', 'Transform an Image',
'resize', 'Resize an Image',
'version', 'Get Version and Copyright',
);
#
# Key words to replace with HTML links
#
my %keywords =
(
AffineMatrix => 'types.html#AffineMatrix',
BlobInfo => 'types.html#BlobInfo',
Cache => 'types.html#Cache',
ChannelType => 'types.html#ChannelType',
ChromaticityInfo => 'types.html#ChromaticityInfo',
ClassType => 'types.html#ClassType',
ClipPathUnits => 'types.html#ClipPathUnits',
ColorPacket => 'types.html#ColorPacket',
ColorspaceType => 'types.html#ColorspaceType',
ComplianceType => 'types.html#ComplianceType',
CompositeOperator => 'types.html#CompositeOperator',
CompressionType => 'types.html#CompressionType',
DecorationType => 'types.html#DecorationType',
DrawContext => 'types.html#DrawContext',
DrawInfo => 'types.html#DrawInfo',
ErrorHandler => 'types.html#ErrorHandler',
ExceptionInfo => 'types.html#ExceptionInfo',
ExceptionType => 'types.html#ExceptionType',
FillRule => 'types.html#FillRule',
FilterTypes => 'types.html#FilterTypes',
FrameInfo => 'types.html#FrameInfo',
GravityType => 'types.html#GravityType',
Image => 'types.html#Image',
ImageInfo => 'types.html#ImageInfo',
ImageType => 'types.html#ImageType',
InterlaceType => 'types.html#InterlaceType',
LayerType => 'types.html#LayerType',
MagickInfo => 'types.html#MagickInfo',
MonitorHandler => 'types.html#MonitorHandler',
MontageInfo => 'types.html#MontageInfo',
NoiseType => 'types.html#NoiseType',
PaintMethod => 'types.html#PaintMethod',
PixelPacket => 'types.html#PixelPacket',
PointInfo => 'types.html#PointInfo',
ProfileInfo => 'types.html#ProfileInfo',
QuantizeInfo => 'types.html#QuantizeInfo',
Quantum => 'types.html#Quantum',
QuantumType => 'types.html#QuantumType',
RectangleInfo => 'types.html#RectangleInfo',
RegistryType => 'types.html#RegistryType',
RenderingIntent => 'types.html#RenderingIntent',
ResolutionType => 'types.html#ResolutionType',
ResourceType => 'types.html#ResourceType',
SegmentInfo => 'types.html#SegmentInfo',
SignatureInfo => 'types.html#SignatureInfo',
StorageType => 'types.html#StorageType',
StreamHandler => 'types.html#StreamHandler',
StretchType => 'types.html#StretchType',
StyleType => 'types.html#StyleType',
TypeMetric => 'types.html#TypeMetric',
CacheView => 'types.html#CacheView',
VirtualPixelMethod => 'types.html#VirtualPixelMethod',
XResourceInfo => 'types.html#XResourceInfo',
);
foreach $src (@srcs) {
my($out,$command);
# Compute POD name
($base = $src) =~ s/\.[^\.]*$//g;
$out = "${base}.${opt_format}";
if ("${opt_outdir}" ne "") {
$out = "${opt_outdir}/${base}.${opt_format}";
}
if ("${opt_srcdir}" ne "") {
$src = "${opt_srcdir}/${src}";
}
$command='pod2html -netscape';
if ( $opt_format eq 'html' ) {
$command='pod2html -netscape';
} elsif ( $opt_format eq 'latex' ) {
$command='pod2latex';
} elsif ( $opt_format eq 'man' ) {
$command='pod2man';
} elsif ( $opt_format eq 'text' ) {
$command='pod2text';
} elsif ( $opt_format eq 'pod' ) {
$command='cat';
}
print( "Processing $src -> $out\n" );
pre_format($src, $tmpname_pre_format); # Make easily parsed
format_to_pod($tmpname_pre_format, $tmpname_pod); # Format to pod.
if ( $opt_format eq 'html' ) {
system("$command $tmpname_pod > \"$tmpname_html\"");
reformat_html($tmpname_html,$out);
} else {
system("$command $tmpname_pod > \"$out\"");
}
unlink($tmpname_pre_format);
unlink($tmpname_pod);
unlink($tmpname_html);
}
#unlink($tmpname_pre_format);
exit(0);
#
# Reformat pod2html-generated HTML into nicer form.
#
sub reformat_html {
my($infile, $outfile) = @_;
open( IN, "<$infile" ) || die("Failed to open \"$infile\" for read\n" );
open( OUT, ">$outfile" ) || die("Failed to open \"$outfile\" for write\n" );
INPUT:
while() {
s|<\!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">|<\!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">|;
s||
|;
s|||;
s||
|;
s||
|;
s|||g;
s|||g;
s|
|
|g;
s|
||g;
s|
|
|g;
s|
||g;
s|
|
|g;
s|
|
|g;
s|
|
|g;
s|
|
|g;
s|
|
|g;
s|
|
|g;
s|||g;
s|>o |>|g;
s|unsignedint|unsigned int|g;
print( OUT $_ );
}
close( TMP );
close( IN );
}
#
# Pre-process file into intermediate form
#
# Initializes globals:
#
# @functions - Function names
# %synopsis - Function synopsis
#
sub pre_format {
my($infile, $tmpfile) = @_;
my $inpara = 0; # Set to 1 if in paragraph
my $inlist = 0; # Set to 1 if in list-item paragraph
# Open C source file
open( IN, "<$infile" ) || die("Failed to open \"$infile\" for read\n" );
# Open TMP file
open( TMP, ">$tmpfile" ) || die("Failed to open \"$tmpfile\" for write\n" );
undef @functions;
undef %synopsis;
# Skip past first form feed
while() {
last if m/\014/;
}
LINE:
while() {
if (m/^\+/) {
while() {
last unless m/^%/;
}
next;
}
next unless m/^%/ ;
chop;
# Extract and save function title
if (m/^%\s+((\w )+)\s+%/) {
($ftitle = $1) =~ s/ //g;
push(@functions, $ftitle);
print( TMP "===$ftitle\n" );
next;
}
# Zap text we don't want
next if ( m/^%.+%/ ); # "%*%
s/^%\s{0,2}//;
# Extract and save synopsis info
if (m /\(\)/ ) {
# nothing
;
}
elsif ( m/${ftitle}\(.*\)$/ ) {
s/,/ , /g;
s/\(/ ( /g;
s/\)/ ) /g;
s/\*/ * /g;
s/\s+/ /g;
s/\(\s+\*/(*/g;
s/ ,/,/g;
s/ \(/(/g;
s/\) /)/g;
s/ \* / */g;
s/^\s*//;
$synopsis{$ftitle} = $_ . ';'; # Append semi-colon, prototype style
print ( TMP " " . $synopsis{$ftitle} . "\n" );
next LINE;
}
elsif ( m/${ftitle}\(.*/ ) {
$synopsis{$ftitle} = $_;
do {
$_ = ;
chop;
# Zap text we don't want
next if m/^%.+%/; # "%*%
s/^%\s{0,2}//;
$synopsis{$ftitle} .= $_;
} until m/^\s*$/;
$_ = $synopsis{$ftitle};
s/,/ , /g;
s/\(/ ( /g;
s/\)/ ) /g;
s/\*/ * /g;
s/\s+/ /g;
s/\(\s+\*/(*/g;
s/ ,/,/g;
s/ \(/(/g;
s/\) /)/g;
s/ \* / */g;
s/^\s*//;
$synopsis{$ftitle} = $_ . ';'; # Append semi-colon, prototype style
print ( TMP " " . $synopsis{$ftitle} . "\n" );
next LINE;
}
# Keep track of paragraphing
if( ! m/^$/ ) {
if ( $inpara == 0 ) {
$inpara = 1; # Start of paragraph
$para = "$_"; # Start paragraph string
} else {
# Inside paragraph
$para .= " $_"; # Add line to paragraph
}
}
# Keep track of list items so they can
# be wrapped as a paragraph
if( m/^\s+(o[^:]+:|o|[0-9]\.)\s(.*)/ ) {
$inlist = 1;
}
if ( $inpara == 1 ) {
if( $para =~ m/^\s+\S+/ && ! $inlist ) {
# Lines that start with a space shouldn't be munged
$inpara = 0; # End of paragraph
$inlist = 0;
$para .= ""; # Terminate paragraph
print( TMP "$para\n" );
}
elsif( m/^$/ ) {
# End of paragraph
$inpara = 0; # End of paragraph
$inlist = 0;
$para .= ""; # Terminate paragraph
$para =~ s/^\s+//g; # Eliminate any leading space
$para =~ s/\s+/ /g; # Canonicalize whitespace
$para =~ s/ $//; # Trim final space
$para =~ s/([a-zA-Z0-9][.!?][)'"]*) /$1 /g; #' Fix sentance ends
print( TMP "\n$para\n\n" );
}
}
}
close( TMP );
close( IN );
}
#
# Second pass
# Process into formatted form
#
sub format_to_pod {
my($infile, $outfile) = @_;
my $func;
my $inlist = 0; # Set to one if in indented list
# Open input file
open( IN, "<$infile" ) || die("Failed to open \"$infile\" for read\n" );
# Open output file
open( OUT, ">$outfile" ) || die("Failed to open \"$outfile\" for write\n" );
# Name field
print( OUT head1("NAME") );
if (!defined($whatis{$base})) {
print("Whatis definition missing for \"$base\"!\n");
print( OUT "${base} - Unknown\n\n" );
} else {
print( OUT "${base} - $whatis{$base}\n\n" );
}
# Synopsis field (function signatures)
print( OUT head1("SYNOPSIS") );
foreach $func (sort( @functions )) {
if (defined $synopsis{$func} ) {
$_ = $synopsis{$func};
s/$func/ B<$func>/;
s/^\s*//;
my $synopsis = $_;
print( OUT $synopsis, "\n\n" );
}
}
# Description field
print( OUT head1("FUNCTION DESCRIPTIONS") );
while(){
chop;
next if m/^$/;
# Match list element
if( m/^(o[^:]+:|o|[0-9]\.?)\s(.*)/ ) {
my $bullet = $1;
my $bullet_text = $2;
print( OUT startlist() ) unless $inlist;
$inlist = 1;
print( OUT item($bullet), "$bullet_text\n\n" );
next;
} else {
print( OUT endlist() ) if $inlist;
$inlist = 0;
}
# Match synopsis item
if( defined $func && m/$func\s*\(.*\)/ ) {
# Split all words with spaces to aid with tokenization
s/,/ , /g;
s/\(/ ( /g;
s/\)/ ) /g;
s/\*/ * /g;
my $html = '';
# Replace tokens matching keywords with HTML links.
TOKEN: foreach $token ( split(' ', $_ ) ) {
foreach $keyword ( %keywords ) {
if ( $token eq $keyword ) {
$html .= linked( $keyword, $keywords{$keyword} );
$html .= " ";
next TOKEN;
}
}
$html .= "$token ";
}
$_ = $html;
# Remove excess spaces
s/\s+/ /g;
s/ ,/,/g;
s/\* /*/g;
s/\)\s*\;/);/;
s/^\s*//;
s/ \( *\)/\(\)/;
# This is very poor because text is output specifically
# for HTML so the text isn't output at all for other target
# formats.
print( OUT html("
$_
") );
next;
}
# Match function title
if( m/===([a-zA-Z0-9]+)/ ) {
$func = $1;
print( OUT head2($func) );
next;
}
print( OUT "\n") if /^[^ ]/;
print( OUT "$_\n") ;
print( OUT "\n") if /^[^ ]/;
}
close( OUT );
close( IN );
}
#
# Return level 1 heading
# Similar to:
heading
#
sub head1 {
my($heading) = @_;
return( "=head1 $heading\n\n" );
}
#
# Return level 2 heading
# Similar to:
heading
#
sub head2 {
my($heading) = @_;
return( "=head2 $heading\n\n" );
}
#
# Return item
# Simlar to:
#
sub item {
my($item) = @_;
return( "=item $item\n\n" );
}
#
# Start list
# Similar to:
#
sub startlist {
return( "=over 4\n\n" )
}
#
# End list
# Similar to:
#
sub endlist {
return( "=back\n\n" );
}
#
# Preformatted text
# Similar to
#
sub formated {
my($text) = @_;
return( " $text\n\n" );
}
#
# Raw HTML paragraph
#
sub html {
my($html) = @_;
return return( "=for html $html\n\n" );
}
#
# HTML Link
# Similar to: description
#
sub linked {
local($description, $url) = @_;
return( "" . $description . "" );
}