1#!/usr/bin/perl -w
2#
3# Format ImageMagick comments into POD-format or HTML format
4# documentation
5# Produces *.pod or *.html files corresponding to *.c files
6#
7# Written by Bob Friesenhahn, April 1997
8#
9
10$opt_format='html';
11$opt_srcdir='';
12$opt_outdir='';
13
14use Getopt::Long;
15if ( ! GetOptions(
16                  'format=s'	=> \$opt_format,
17                  'srcdir=s'	=> \$opt_srcdir,
18                  'outdir=s'	=> \$opt_outdir,
19                 )
20   ) {
21  print("Usage: fmtdocs [-srcdir srcdir] [-outdir outdir] [-format format] \n");
22  exit(1);
23}
24
25#
26# Source files to use
27#
28@srcs = ('animate.c',
29	 'annotate.c',
30	 'attribute.c',
31	 'blob.c',
32	 'cache.c',
33	 'cache-view.c',
34	 'color.c',
35	 'colorspace.c',
36	 'compare.c',
37	 'composite.c',
38	 'constitute.c',
39	 'decorate.c',
40   'deprecate.c',
41	 'draw.c',
42	 'drawing-wand.c',
43	 'display.c',
44	 'effect.c',
45	 'enhance.c',
46	 'exception.c',
47	 'fx.c',
48	 'image.c',
49	 'list.c',
50	 'magick.c',
51	 'magick-wand.c',
52	 'memory.c',
53	 'monitor.c',
54	 'montage.c',
55   'paint.c',
56	 'pixel-iterator.c',
57	 'pixel-wand.c',
58	 'profile.c',
59	 'quantize.c',
60	 'registry.c',
61   'resource.c',
62	 'segment.c',
63	 'shear.c',
64	 'signature.c',
65	 'stream.c',
66	 'transform.c',
67	 'resize.c',
68   'version.c');
69
70$tmpname_pre_format = "/tmp/fmtdocs_pre.$$";
71$tmpname_pod = "/tmp/fmtdocs_pod.$$";
72$tmpname_html = "/tmp/fmtdocs_html.$$";
73
74#@srcs = ('draw.c');
75
76#
77# What is for source files
78#
79%whatis =
80(
81 'animate',	'Interactively Animate an Image Sequence',
82 'annotate',	'Annotate an Image',
83 'attribute',	'Set Text Attributes',
84 'blob',	'Read or Write Binary Large OBjects',
85 'color',	'Count the Colors in an Image',
86 'colorspace',	'Dealing with Image Colorspaces',
87 'compare',	'Compare an Image to a Reconstructed Image',
88 'constitute',	'Constitute an Image',
89 'composite',	'Composite an Image',
90 'decorate',	'Decorate an Image',
91 'deprecate',	'Deprecated Methods',
92 'display',	'Interactively Display and Edit an Image',
93 'draw',	'Draw on an Image',
94 'drawing_wand',	'Image Vector Drawing',
95 'effect',	'Add an Effect',
96 'fx',		'Add a Special Effect',
97 'enhance',	'Enhance an Image',
98 'exception',	'Dealing with Exceptions',
99 'image',	'Image Methods',
100 'list',	'Working with Image Lists',
101 'cache',	'Get or Set Image Pixels',
102 'cache_view',	'Working with Cache Views',
103 'magick',	'Read or List Image formats',
104 'magick_wand',	'Magick Wand',
105 'memory',	'Memory Allocation',
106 'monitor',	'Monitor the Progress of an Image Operation',
107 'montage',	'Create an Image Thumbnail',
108 'paint',	'Paint on an Image',
109 'pixel_iterator',	'Pixel Iterator',
110 'pixel_wand',	'Pixel Wand',
111 'profile',	'Dealing with Image Profiles',
112 'quantize',	'Reduce the Number of Unique Colors in an Image',
113 'registry',	'The Registry',
114 'resource',	'Minitor or Limit Resource Consumption',
115 'segment',	'Segment an Image with Thresholding Fuzzy c-Means',
116 'shear',	'Shear or Rotate an Image by an Arbitrary Angle',
117 'signature',	'Compute a Digital Signature for an Image',
118 'stream',	'The Pixel FIFO',
119 'transform',	'Transform an Image',
120 'resize',	'Resize an Image',
121 'version',	'Get Version and Copyright',
122);
123
124#
125# Key words to replace with HTML links
126#
127my %keywords =
128  (
129   AffineMatrix		=> 'types.html#AffineMatrix',
130   BlobInfo		=> 'types.html#BlobInfo',
131   Cache		=> 'types.html#Cache',
132   ChannelType		=> 'types.html#ChannelType',
133   ChromaticityInfo	=> 'types.html#ChromaticityInfo',
134   ClassType		=> 'types.html#ClassType',
135   ClipPathUnits	=> 'types.html#ClipPathUnits',
136   ColorPacket		=> 'types.html#ColorPacket',
137   ColorspaceType	=> 'types.html#ColorspaceType',
138   ComplianceType	=> 'types.html#ComplianceType',
139   CompositeOperator	=> 'types.html#CompositeOperator',
140   CompressionType	=> 'types.html#CompressionType',
141   DecorationType	=> 'types.html#DecorationType',
142   DrawContext		=> 'types.html#DrawContext',
143   DrawInfo		=> 'types.html#DrawInfo',
144   ErrorHandler		=> 'types.html#ErrorHandler',
145   ExceptionInfo	=> 'types.html#ExceptionInfo',
146   ExceptionType	=> 'types.html#ExceptionType',
147   FillRule		=> 'types.html#FillRule',
148   FilterTypes		=> 'types.html#FilterTypes',
149   FrameInfo		=> 'types.html#FrameInfo',
150   GravityType		=> 'types.html#GravityType',
151   Image		=> 'types.html#Image',
152   ImageInfo		=> 'types.html#ImageInfo',
153   ImageType		=> 'types.html#ImageType',
154   InterlaceType	=> 'types.html#InterlaceType',
155   LayerType		=> 'types.html#LayerType',
156   MagickInfo		=> 'types.html#MagickInfo',
157   MonitorHandler	=> 'types.html#MonitorHandler',
158   MontageInfo		=> 'types.html#MontageInfo',
159   NoiseType		=> 'types.html#NoiseType',
160   PaintMethod		=> 'types.html#PaintMethod',
161   PixelPacket		=> 'types.html#PixelPacket',
162   PointInfo		=> 'types.html#PointInfo',
163   ProfileInfo		=> 'types.html#ProfileInfo',
164   QuantizeInfo		=> 'types.html#QuantizeInfo',
165   Quantum		=> 'types.html#Quantum',
166   QuantumType		=> 'types.html#QuantumType',
167   RectangleInfo	=> 'types.html#RectangleInfo',
168   RegistryType		=> 'types.html#RegistryType',
169   RenderingIntent	=> 'types.html#RenderingIntent',
170   ResolutionType	=> 'types.html#ResolutionType',
171   ResourceType		=> 'types.html#ResourceType',
172   SegmentInfo		=> 'types.html#SegmentInfo',
173   SignatureInfo	=> 'types.html#SignatureInfo',
174   StorageType		=> 'types.html#StorageType',
175   StreamHandler	=> 'types.html#StreamHandler',
176   StretchType		=> 'types.html#StretchType',
177   StyleType		=> 'types.html#StyleType',
178   TypeMetric		=> 'types.html#TypeMetric',
179   CacheView		=> 'types.html#CacheView',
180   VirtualPixelMethod	=> 'types.html#VirtualPixelMethod',
181   XResourceInfo	=> 'types.html#XResourceInfo',
182);
183
184
185foreach $src (@srcs) {
186
187  my($out,$command);
188
189  # Compute POD name
190  ($base = $src) =~ s/\.[^\.]*$//g;
191
192  $out = "${base}.${opt_format}";
193  if ("${opt_outdir}" ne "") {
194    $out = "${opt_outdir}/${base}.${opt_format}";
195  }
196
197  if ("${opt_srcdir}" ne "") {
198    $src = "${opt_srcdir}/${src}";
199  }
200
201  $command='pod2html -netscape';
202  if ( $opt_format eq 'html' ) {
203    $command='pod2html -netscape';
204  } elsif ( $opt_format eq 'latex' ) {
205    $command='pod2latex';
206  } elsif ( $opt_format eq 'man' ) {
207    $command='pod2man';
208  } elsif ( $opt_format eq 'text' ) {
209    $command='pod2text';
210  } elsif ( $opt_format eq 'pod' ) {
211    $command='cat';
212  }
213
214  print( "Processing $src -> $out\n" );
215
216  pre_format($src, $tmpname_pre_format);		# Make easily parsed
217  format_to_pod($tmpname_pre_format, $tmpname_pod);	# Format to pod.
218
219  if ( $opt_format eq 'html' ) {
220    system("$command $tmpname_pod > \"$tmpname_html\"");
221    reformat_html($tmpname_html,$out);
222  } else {
223    system("$command $tmpname_pod > \"$out\"");
224  }
225  unlink($tmpname_pre_format);
226  unlink($tmpname_pod);
227  unlink($tmpname_html);
228}
229
230#unlink($tmpname_pre_format);
231exit(0);
232
233#
234# Reformat pod2html-generated HTML into nicer form.
235#
236sub reformat_html {
237  my($infile, $outfile) = @_;
238
239  open( IN, "<$infile" ) || die("Failed to open \"$infile\" for read\n" );
240  open( OUT, ">$outfile" ) || die("Failed to open \"$outfile\" for write\n" );
241
242 INPUT:
243  while(<IN>) {
244    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"
245  "http://www.w3.org/TR/html4/loose.dtd">|;
246    s|<HEAD>|<HEAD>
247<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8">
248<STYLE>
249<!--
250\@page { size: 8.5in 11in }
251TD P { color: #000000; font-family: "Verdana", "Arial", "Helvetica", sans-serif; font-size: 12pt }
252P { color: #000000; font-family: "Verdana", "Arial", "Helvetica", sans-serif; font-size: 12pt }
253H2 { color: #000000 }
254A:link { color: #0085c0 }
255A:visited { color: #800080 }
256-->
257</STYLE>
258|;
259    s|<link rev="made" href="mailto:root\@localhost" />|<link rel="stylesheet" type="text/css" href="../magick.css">|;
260    s|<body style="background-color: white">|<body marginheight="1" marginwidth="1" topmargin="1" leftmargin="1">
261<a name="top"></a> 
262<table border="0" cellpadding="0" cellspacing="0" summary="Masthead" width="100%">
263<tbody>
264<tr>
265<td bgcolor="#003399" width="25%" height="118" background="../../images/background.gif"><a href="http://www.imagemagick.org/"><img src="../../images/script.gif" width="278" height="118" border="0" alt="" /></a></td>
266<td bgcolor="#003399" width="60%" height="118" background="../../images/background.gif"><a href="http://www.networkeleven.com/direct.php?magick_all"><img src="../../images/promote.png" border="0" width="186" height="52" vspace="29" alt="Powered by NetworkEleven" /></a></td>
267<td bgcolor="#003399" width="114" height="118" align="right"><img src="../../images/sprite.png" width="114" height="118" alt="" /></td>
268<td bgcolor="#003399" width="114" height="118" align="right"><a href="http://www.imagemagick.net"><img src="../../images/logo.png" width="114" height="118" border="0" alt="ImageMagick logo" /></a></td>
269</tr></tbody></table>
270<table align="left" border="0" cellpadding="2" cellspacing="2" summary="Navigation buttons" width="20%">
271<tr>
272<td>
273<form target="_self" action="../../index.html"><input type="submit" title="ImageMagick Home" value=" Home" style="background-color: #1947A3; background-image:url('../../../images/background.gif'); color:#fbc713; font-weight:bold"></form></td>
274<td>
275<form target="_self" action="../../www/apis.html"><input type="submit" title="ImageMagick API" value=" API " style="background-color: #1947A3; background-image:url('../../../images/background.gif'); color:#fbc713; font-weight:bold"></form></td>
276<td>
277<form target="_self" action="../../www/download.html"><input type="submit" title="ImageMagick Download" value="Download" style="background-color: #1947A3; background-image:url('../../../images/background.gif'); color:#fbc713; font-weight:bold"></form></td></tr></table>
278<div align="right" style="margin-top:3px; padding-right:4px">
279<form action="http://studio.imagemagick.org/Sage/scripts/Sage.cgi"><input type="TEXT" name="query" size="32" maxlength="255"> <input type="SUBMIT" name="sa" value="Search" style="background-color: #1947A3; background-image:url('../../../images/background.gif'); bgcolor:#003399; color:#fbc713; font-weight:bold"></form></div>
280<table align="left" border="0" cellpadding="10" cellspacing="0" style="margin-top:-17px" width="100%">
281<tr>
282<td>
283|;
284    s|</body>|
285<HR>
286
287<a href="#top"><img src="../../../images/top.gif" border=0 width="35" height="46" align="right" alt="Top of page"></a>
288<form action="http://studio.imagemagick.org/magick/" style="margin-top:5px">
289<input type="submit" title="Help!" value="Help!" style="background-image:url('../../../images/background.gif'); color:#fbc713; font-weight:bold">
290  <small>&quot;Image manipulation software that works like magick&quot;</small>
291</form></td>
292</tr></table>
293
294</body>
295|;
296    s|<FONT SIZE=-1>||g;
297    s|</FONT>||g;
298
299    s|<H2>|<H3>|g;
300    s|</H2>|</H3>|g;
301
302    s|<H1>|<H2>|g;
303    s|</H1>|</H2>|g;
304
305    s|<DT>|<DD><P></P><DT>|g;
306    s|<DL>|<DL><DT><DD><DL>|g;
307    s|</DL>|</DL></DL>|g;
308    s|<dd>|<DD>|g;
309    s|<p>|<P>|g;
310    s|</p>|</P>|g;
311    s|</LI>||g;
312    s|>o |>|g;
313    s|unsignedint|unsigned int|g;
314    print( OUT $_ );
315  }
316  close( TMP );
317  close( IN );
318}
319
320#
321# Pre-process file into intermediate form
322#
323# Initializes globals:
324#
325#  @functions	- Function names
326#  %synopsis	- Function synopsis
327#
328sub pre_format {
329  my($infile, $tmpfile) = @_;
330
331  my $inpara = 0;	# Set to 1 if in paragraph
332  my $inlist = 0;	# Set to 1 if in list-item paragraph
333
334  # Open C source file
335  open( IN, "<$infile" ) || die("Failed to open \"$infile\" for read\n" );
336
337  # Open TMP file
338  open( TMP, ">$tmpfile" ) || die("Failed to open \"$tmpfile\" for write\n" );
339
340  undef @functions;
341  undef %synopsis;
342
343  # Skip past first form feed
344  while(<IN>) {
345    last if m/\014/;
346  }
347
348LINE:
349  while(<IN>) {
350    if (m/^\+/) {
351      while(<IN>) {
352	last unless m/^%/;
353      }
354      next;
355    }
356    next unless m/^%/ ;
357    chop;
358
359    # Extract and save function title
360    if (m/^%\s+((\w )+)\s+%/) {
361      ($ftitle = $1) =~ s/ //g;
362      push(@functions, $ftitle);
363      print( TMP "===$ftitle\n" );
364      next;
365    }
366
367    # Zap text we don't want
368    next if ( m/^%.+%/ );	# "%*%
369    s/^%\s{0,2}//;
370
371    # Extract and save synopsis info
372    if (m /\(\)/ ) {
373      # nothing
374      ;
375    }
376    elsif ( m/${ftitle}\(.*\)$/ ) {
377      s/,/ , /g;
378      s/\(/ ( /g;
379      s/\)/ ) /g;
380      s/\*/ * /g;
381      s/\s+/ /g;
382
383      s/\(\s+\*/(*/g;
384      s/ ,/,/g;
385      s/ \(/(/g;
386      s/\) /)/g;
387      s/ \* / */g;
388
389      s/^\s*//;
390      $synopsis{$ftitle} = $_ . ';'; # Append semi-colon, prototype style
391      print ( TMP " " . $synopsis{$ftitle} . "\n" );
392      next LINE;
393     }
394     elsif ( m/${ftitle}\(.*/ ) {
395      $synopsis{$ftitle} = $_;
396      do {
397	$_ = <IN>;
398	chop;
399	# Zap text we don't want
400	next if m/^%.+%/;	# "%*%
401	s/^%\s{0,2}//;
402	$synopsis{$ftitle} .= $_;
403      } until m/^\s*$/;
404      $_ = $synopsis{$ftitle};
405
406      s/,/ , /g;
407      s/\(/ ( /g;
408      s/\)/ ) /g;
409      s/\*/ * /g;
410      s/\s+/ /g;
411
412      s/\(\s+\*/(*/g;
413      s/ ,/,/g;
414      s/ \(/(/g;
415      s/\) /)/g;
416      s/ \* / */g;
417
418      s/^\s*//;
419      $synopsis{$ftitle} = $_ . ';'; # Append semi-colon, prototype style
420      print ( TMP " " . $synopsis{$ftitle} . "\n" );
421      next LINE;
422    }
423
424  # Keep track of paragraphing
425  if( ! m/^$/ ) {
426    if ( $inpara == 0 ) {
427      $inpara = 1;	# Start of paragraph
428      $para = "$_";	# Start paragraph string
429    } else {
430      # Inside paragraph
431      $para .= " $_";	# Add line to paragraph
432    }
433  }
434  # Keep track of list items so they can
435  # be wrapped as a paragraph
436  if( m/^\s+(o[^:]+:|o|[0-9]\.)\s(.*)/ ) {
437    $inlist = 1;
438  }
439
440  if ( $inpara == 1 ) {
441    if( $para =~ m/^\s+\S+/ && ! $inlist ) {
442      # Lines that start with a space shouldn't be munged
443      $inpara = 0;	# End of paragraph
444      $inlist = 0;
445      $para .= "";	# Terminate paragraph
446      print( TMP "$para\n" );
447    }
448    elsif( m/^$/ ) {
449      # End of paragraph
450      $inpara = 0;	# End of paragraph
451      $inlist = 0;
452      $para .= "";	# Terminate paragraph
453      $para =~ s/^\s+//g;		# Eliminate any leading space
454      $para =~ s/\s+/ /g;		# Canonicalize whitespace
455      $para =~ s/ $//;		# Trim final space
456      $para =~ s/([a-zA-Z0-9][.!?][)'"]*) /$1  /g; #' Fix sentance ends
457		  print( TMP "\n$para\n\n" );
458		}
459    }
460  }
461
462  close( TMP );
463  close( IN );
464}
465
466#
467# Second pass
468# Process into formatted form
469#
470sub format_to_pod {
471    my($infile, $outfile) = @_;
472
473    my $func;
474
475    my $inlist = 0;		# Set to one if in indented list
476
477    # Open input file
478    open( IN, "<$infile" ) || die("Failed to open \"$infile\" for read\n" );
479
480    # Open output file
481    open( OUT, ">$outfile" ) || die("Failed to open \"$outfile\" for write\n" );
482
483    # Name field
484    print( OUT head1("NAME") );
485    if (!defined($whatis{$base})) {
486      print("Whatis definition missing for \"$base\"!\n");
487      print( OUT "${base} - Unknown\n\n" );
488    } else {
489      print( OUT "${base} - $whatis{$base}\n\n" );
490    }
491
492    # Synopsis field (function signatures)
493    print( OUT head1("SYNOPSIS") );
494    foreach $func (sort( @functions )) {
495      if (defined $synopsis{$func} ) {
496	$_ = $synopsis{$func};
497	s/$func/ B<$func>/;
498	s/^\s*//;
499	my $synopsis = $_;
500	print( OUT $synopsis, "\n\n" );
501      }
502    }
503
504    # Description field
505    print( OUT head1("FUNCTION DESCRIPTIONS") );
506
507    while(<IN>){
508	chop;
509	next if m/^$/;
510
511	# Match list element
512	if( m/^(o[^:]+:|o|[0-9]\.?)\s(.*)/ ) {
513	    my $bullet = $1;
514	    my $bullet_text = $2;
515
516	    print( OUT startlist() ) unless $inlist;
517	    $inlist = 1;
518	    print( OUT item($bullet), "$bullet_text\n\n" );
519	    next;
520	} else {
521	    print( OUT endlist() ) if $inlist;
522	    $inlist = 0;
523	}
524
525	# Match synopsis item
526	if( defined $func && m/$func\s*\(.*\)/ ) {
527	  # Split all words with spaces to aid with tokenization
528	  s/,/ , /g;
529	  s/\(/ ( /g;
530	  s/\)/ ) /g;
531	  s/\*/ * /g;
532
533	  my $html = '';
534
535	  # Replace tokens matching keywords with HTML links.
536TOKEN:	  foreach $token ( split(' ', $_ ) ) {
537	    foreach $keyword ( %keywords ) {
538	      if ( $token eq $keyword ) {
539		$html .= linked( $keyword, $keywords{$keyword} );
540		$html .= " ";
541		next TOKEN;
542	      }
543	    }
544	    $html .= "$token ";
545	  }
546	  $_ = $html;
547	  # Remove excess spaces
548	  s/\s+/ /g;
549	  s/ ,/,/g;
550	  s/\* /*/g;
551	  s/\)\s*\;/);/;
552	  s/^\s*//;
553          s/ \( *\)/\(\)/;
554
555          # This is very poor because text is output specifically
556          # for HTML so the text isn't output at all for other target
557          # formats.
558	  print( OUT html("<blockquote>$_</blockquote>") );
559	    next;
560	}
561
562	# Match function title
563	if( m/===([a-zA-Z0-9]+)/ ) {
564	    $func = $1;
565	    print( OUT head2($func) );
566	    next;
567	}
568
569        print( OUT "\n") if /^[^ ]/;
570	print( OUT "$_\n") ;
571        print( OUT "\n") if /^[^ ]/;
572    }
573
574    close( OUT );
575    close( IN );
576}
577
578#
579# Return level 1 heading
580# Similar to: <H1>heading</H1>
581#
582sub head1 {
583    my($heading) = @_;
584    return( "=head1 $heading\n\n" );
585}
586
587#
588# Return level 2 heading
589# Similar to: <H2>heading</H2>
590#
591sub head2 {
592    my($heading) = @_;
593    return( "=head2 $heading\n\n" );
594}
595
596
597#
598# Return item
599# Simlar to: <I>
600#
601sub item {
602    my($item) = @_;
603    return( "=item $item\n\n" );
604}
605
606
607#
608# Start list
609# Similar to: <UL>
610#
611sub startlist {
612    return( "=over 4\n\n" )
613}
614
615#
616# End list
617# Similar to: </UL>
618#
619sub endlist {
620    return( "=back\n\n" );
621}
622
623#
624# Preformatted text
625# Similar to <PRE></PRE>
626#
627sub formated {
628    my($text) = @_;
629    return( " $text\n\n" );
630}
631
632#
633# Raw HTML paragraph
634#
635sub html {
636  my($html) = @_;
637  return return( "=for html $html\n\n" );
638}
639
640#
641# HTML Link
642# Similar to: <A HREF="url">description</A>
643#
644sub linked {
645  local($description, $url) = @_;
646  return( "<A HREF=\"" . $url . "\">" . $description . "</A>" );
647}
648