#!/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',
	 'composite.c',
	 'constitute.c',
	 'decorate.c',
         'deprecate.c',
	 'render.c',
	 'draw.c',
	 'display.c',
	 'effect.c',
	 'enhance.c',
	 'error.c',
	 'fx.c',
	 'image.c',
	 'list.c',
	 'magick.c',
	 'memory.c',
	 'monitor.c',
	 'montage.c',
         'paint.c',
	 'quantize.c',
	 'registry.c',
         'resource.c',
	 'segment.c',
	 'shear.c',
	 'signature.c',
	 'stream.c',
	 'transform.c',
	 'resize.c',
         'widget.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',	'Methods to Interactively Animate an Image Sequence',
 'annotate',	'Methods to Annotate an Image',
 'attribute',	'Image Text Attributes Methods',
 'blob',	'Methods to Read or Write Binary Large OBjects',
 'color',	'Methods to Count the Colors in an Image',
 'constitute',	'Methods to Constitute an Image',
 'composite',	'Methods to Composite an Image',
 'decorate',	'GraphicsMagick Image Decoration Methods',
 'deprecate',	'GraphicsMagick Deprecated Methods',
 'display',	'Methods to Interactively Display and Edit an Image',
 'render',	'Methods to Draw on an Image',
 'draw',	'Image Vector Drawing Methods',
 'effect',	'GraphicsMagick Image Effects Methods',
 'fx',		'GraphicsMagick Special Effects Methods',
 'enhance',	'Methods to Enhance an Image',
 'error',	'GraphicsMagick Error Methods',
 'image',	'GraphicsMagick Image Methods',
 'list',	'Working with Image Lists',
 'cache',	'Methods to Get or Set Image Pixels',
 'cache_view',	'GraphicsMagick Cache Views Methods',
 'magick',	'Methods to Read or List GraphicsMagick Image formats',
 'memory',	'GraphicsMagick Memory Allocation Methods',
 'monitor',	'GraphicsMagick Progress Monitor Methods',
 'montage',	'Methods to Create a Montage',
 'paint',	'Methods to Paint on an Image',
 'quantize',	'Methods to Reduce the Number of Unique Colors in an Image',
 'registry',	'GraphicsMagick Registry Methods',
 'resource',	'GraphicsMagick Resource Consumption Methods',
 'segment',	'Methods to Segment an Image with Thresholding Fuzzy c-Means',
 'shear',	'Methods to Shear or Rotate an Image by an Arbitrary Angle',
 'signature',	'Methods to Compute a Digital Signature for an Image',
 'stream',	'Image Pixel FIFO',
 'transform',	'Methods to Transform an Image',
 'resize',	'Methods to Resize an Image',
 'widget',	'GraphicsMagick X11 Widgets'
);

#
# 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',
   ViewInfo		=> 'types.html#ViewInfo',
   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(<IN>) {
    s|<HTML>|<\!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"<HTML>|;
    s|<HTML>| "http://www.w3.org/TR/html4/loose.dtd"><HTML>|;
    s|<HEAD>|<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8">
<STYLE>
<!--
\@page { size: 8.5in 11in }
TD P { color: #000000; font-family: "Verdana", "Arial", "Helvetica", sans-serif; font-size: 14pt }
P { color: #000000; font-family: "Verdana", "Arial", "Helvetica", sans-serif; font-size: 14pt }
H2 { color: #000000 }
A:link { color: #0085c0 }
A:visited { color: #800080 }
-->
</STYLE>
|;
    s|<BODY>|<BODY LANG="en-US" TEXT="#000000" LINK="#0085c0" VLINK="#800080" BGCOLOR="#ffffff">
<FORM ACTION="http://www.google.com/search">
        <INPUT TYPE=HIDDEN NAME="domains" VALUE="www.graphicsmagick.org">
        <INPUT TYPE=HIDDEN NAME="sitesearch" VALUE="www.graphicsmagick.org">
        <TABLE WIDTH=100% BORDER=1 BORDERCOLOR="#000000" CELLPADDING=4 CELLSPACING=0 RULES=NONE STYLE="page-break-before: always">
                <COL WIDTH=208*>
                <COL WIDTH=48*>
                <TR>
                        <TD WIDTH=81%>
                                <P ALIGN=LEFT>[<A HREF="../../index.html">Home</A>] [<A HREF="../mission.html">Mission
                                Statement</A>] [<A HREF="../development.html">Development Process</A>] [<A HREF="../download.html">Download</A>]
                                [<A HREF="../install.html">Installation</A>] [<A HREF="../cvs.html">CVS</A>]
                                [<A HREF="http://sourceforge.net/mail/?group_id=73485">Mailing
                                Lists</A>] [<A HREF="../FAQ.html">FAQ</A>] [<A HREF="../formats.html">Formats</A>]
                                [<A HREF="../NEWS.html">News</A> ] [<A HREF="../Changelog.html"><SPAN LANG="en-US">ChangeLog</SPAN></A>]
                                [<A HREF="http://sourceforge.net/projects/graphicsmagick/">Report
                                Bugs</A>] [<A HREF="../utilities.html">Utilities</A>] [<A HREF="../programming.html">Programming</A>]
                                [<A HREF="../books.html">Books</A>] [<A HREF="../links.html">Links</A>]</P>
                        </TD>
                        <TD ROWSPAN=2 WIDTH=19%>
                                <P ALIGN=CENTER><IMG SRC="../../images/magick_small.png" NAME="Graphic2" ALIGN=BOTTOM WIDTH=114 HEIGHT=118 BORDER=0></P>
                        </TD>
                </TR>
                <TR>
                        <TD WIDTH=81%>
                                <DIV ALIGN=CENTER>
                                        <P><I>Search GraphicsMagick site <INPUT TYPE=TEXT NAME="q" SIZE=20 MAXLENGTH=255>
                                        <INPUT TYPE=SUBMIT NAME="sa" VALUE="Search"> </I>
                                        </P>
                                </DIV>
                        </TD>
                </TR>
        </TABLE>
</FORM>
|;
    s|<FONT SIZE=-1>||g;
    s|</FONT>||g;

    s|<H2>|<H3>|g;
    s|</H2>|</H3>|g;

    s|<H1>|<H2>|g;
    s|</H1>|</H2>|g;

    s|<DT>|<DD><P></P><DT>|g;
    s|<DL>|<DL><DT><DD><DL>|g;
    s|</DL>|</DL></DL>|g;
    s|<dd>|<DD>|g;
    s|<p>|<P>|g;
    s|</p>|</P>|g;
    s|</LI>||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(<IN>) {
    last if m/\014/;
  }

LINE:
  while(<IN>) {
    if (m/^\+/) {
      while(<IN>) {
	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 {
	$_ = <IN>;
	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(<IN>){
	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("<blockquote>$_</blockquote>") );
	    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: <H1>heading</H1>
#
sub head1 {
    my($heading) = @_;
    return( "=head1 $heading\n\n" );
}

#
# Return level 2 heading
# Similar to: <H2>heading</H2>
#
sub head2 {
    my($heading) = @_;
    return( "=head2 $heading\n\n" );
}


#
# Return item
# Simlar to: <I>
#
sub item {
    my($item) = @_;
    return( "=item $item\n\n" );
}


#
# Start list
# Similar to: <UL>
#
sub startlist {
    return( "=over 4\n\n" )
}

#
# End list
# Similar to: </UL>
#
sub endlist {
    return( "=back\n\n" );
}

#
# Preformatted text
# Similar to <PRE></PRE>
#
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: <A HREF="url">description</A>
#
sub linked {
  local($description, $url) = @_;
  return( "<A HREF=\"" . $url . "\">" . $description . "</A>" );
}
