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>"Image manipulation software that works like magick"</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