1#!/usr/bin/perl 2 3## Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Simon Josefsson 4## added -texinfo, -listfunc 5## man page revamp 6## various improvements 7## Copyright (c) 2001, 2002, 2013 Nikos Mavrogiannopoulos 8## added -tex, -pkg-site 9## Copyright (c) 1998 Michael Zucchi 10## Copyright (c) 2013 Adam Sampson 11## made highlighting not depend on hash order, for Perl 5.18 12 13# This program is free software: you can redistribute it and/or modify 14# it under the terms of the GNU General Public License as published by 15# the Free Software Foundation, either version 3 of the License, or 16# (at your option) any later version. 17# 18# This program is distributed in the hope that it will be useful, 19# but WITHOUT ANY WARRANTY; without even the implied warranty of 20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21# GNU General Public License for more details. 22# 23# You should have received a copy of the GNU General Public License 24# along with this program. If not, see <https://www.gnu.org/licenses/>. 25 26# This will read a C source code file and scan for embedded comments 27# in the style of gnome comments (+minor extensions - see below). 28 29# usage: 30# gdoc [ -docbook | -html | -text | -man | -tex | -texinfo | -listfunc ] 31# [ -sourceversion verno ] [ -include file | -includefuncprefix ] 32# [ -bugsto address ] [ -pkg-site website ] 33# [ -seeinfo infonode ] [ -copyright notice ] [ -verbatimcopying ] 34# [ -function funcname [ -function funcname ...] ] c file(s)s > outputfile 35# 36# Set output format using one of -docbook, -html, -text, -man, -tex, 37# -texinfo, or -listfunc. Default is man. 38# 39# -sourceversion 40# Version number for source code, e.g. '1.0.4'. Used in 'man' headers. 41# Defaults to using current date. 42# 43# -include FILE 44# For man pages, mention #include <FILE.h> in the synopsis. 45# 46# -includefuncprefix 47# For man pages, mention a #include <FILE.h> in the synopsis. 48# The FILE derived from the function prefix. For example, a 49# function gss_init_sec_context will generate an include 50# statement of #include <gss.h>. 51# 52# -bugsto address 53# For man pages, include a section about reporting bugs and mention 54# the given e-mail address, e.g 'bug-libidn@gnu.org'. 55# 56# -pkg-site web-site 57# For man pages when -bugsto is used, also include help URLs to the 58# the project's home page. 59# 60# -seeinfo infonode 61# For man pages, include a section that point to an info manual 62# for more information. 63# 64# -copyright notice 65# For man pages, include a copyright section with the given 66# notice after a preamble. Use, e.g., '2002, 2003 Simon Josefsson'. 67# 68# -verbatimcopying 69# For man pages, and when the -copyright parameter is used, 70# add a licensing statement that say verbatim copying is permitted. 71# 72# -function funcname 73# If set, then only generate documentation for the given function(s). All 74# other functions are ignored. 75# 76# c files - list of 'c' files to process 77# 78# All output goes to stdout, with errors to stderr. 79 80# 81# format of comments. 82# In the following table, (...)? signifies optional structure. 83# (...)* signifies 0 or more structure elements 84# /** 85# * function_name(:)? (- short description)? 86# (* @parameterx: (description of parameter x)?)* 87# (* a blank line)? 88# * (Description:)? (Description of function)? 89# * (Section header: (section description)? )* 90# (*)?*/ 91# 92# So .. the trivial example would be: 93# 94# /** 95# * my_function 96# **/ 97# 98# If the Description: header tag is omitted, then there must be a blank line 99# after the last parameter specification. 100# e.g. 101# /** 102# * my_function - does my stuff 103# * @my_arg: its mine damnit 104# * 105# * Does my stuff explained. 106# */ 107# 108# or, could also use: 109# /** 110# * my_function - does my stuff 111# * @my_arg: its mine damnit 112# * Description: Does my stuff explained. 113# */ 114# etc. 115# 116# All descriptions can be multiline, apart from the short function description. 117# 118# All descriptive text is further processed, scanning for the following special 119# patterns, which are highlighted appropriately. 120# 121# 'funcname()' - function 122# '$ENVVAR' - environmental variable OBSOLETE (?) 123# '#struct_name' - name of a structure 124# '@parameter' - name of a parameter 125# '%CONST' - name of a constant. 126 127# 128# Extensions for LaTeX: 129# 130# 1. the symbol '->' will be replaced with a rightarrow 131# 2. x^y with ${x}^{y}$. 132# 3. xxx\: with xxx: 133 134use POSIX qw(strftime); 135 136# match expressions used to find embedded type information 137$type_constant = '(?<!\%)\%([A-Za-z0-9_]+)'; 138$type_func = "([A-Za-z0-9_]+\\(\\))"; 139$type_param = '(?<!\@)\@([A-Za-z0-9_]+)\s*'; 140$type_struct = "\\\#([A-Za-z0-9_]+)"; 141$type_env = "(\\\$[A-Za-z0-9_]+)"; 142 143 144# Output conversion substitutions. 145# One for each output format 146 147# these work fairly well 148@highlights_html = ( [$type_constant, '"<i>$1</i>"'], 149 [$type_func, '"<b>$1</b>"'], 150 [$type_struct, '"<i>$1</i>"'], 151 [$type_param, '" <tt><b>$1</b></tt> "'], 152 ['\%\%', '"\%"'] 153 ); 154$blankline_html = "<p>"; 155 156@highlights_texinfo = ( [$type_param, '" \@code{$1} "'], 157 [$type_constant, '"\@code{$1} "'], 158 [$type_func, '"\@code{$1} "'], 159 [$type_struct, '"\@code{$1} "'], 160 ['\%\%', '"\%"'], 161 ); 162$blankline_texinfo = ""; 163 164@highlights_tex = ( [$type_param, '" {\\\bf $1} "'], 165 [$type_constant, '"{\\\it $1}"'], 166 [$type_func, '"{\\\bf $1}"'], 167 [$type_struct, '"{\\\it $1}"'], 168 ['\@\@', '"\@"'] 169 ); 170$blankline_tex = "\\\\"; 171 172# sgml, docbook format 173@highlights_sgml = ( [$type_constant, '"<replaceable class=\"option\">$1</replaceable>"'], 174 [$type_func, '"<function>$1</function>"'], 175 [$type_struct, '"<structname>$1</structname>"'], 176 [$type_env, '"<envar>$1</envar>"'], 177 [$type_param, '" <parameter>$1</parameter> "'] ); 178$blankline_sgml = "</para><para>\n"; 179 180# these are pretty rough 181@highlights_man = ( [$type_constant, '"\\\fB$1\\\fP"'], 182 [$type_func, '"\\\fB$1\\\fP"'], 183 [$type_struct, '"\\\fB$1\\\fP"'], 184 [$type_param, '" \\\fI$1\\\fP "'], 185 ['\%\%', '"\%"'], 186 ['\@\@', '"\@"']); 187$blankline_man = ""; 188 189# text-mode 190@highlights_text = ( [$type_constant, '"$1"'], 191 [$type_func, '"$1"'], 192 [$type_struct, '"$1"'], 193 [$type_param, '"$1 "'], 194 ['\%\%', '"\%"'], 195 ['\@\@', '"\@"']); 196$blankline_text = ""; 197my $lineprefix = ""; 198 199my $function_found = 0; 200 201sub usage { 202 print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man | -tex | -texinfo -listfunc ]\n"; 203 print " [ -sourceversion verno ] [ -include file | -includefuncprefix ]\n"; 204 print " [ -bugsto address ] [ -seeinfo infonode ] [ -copyright notice]\n"; 205 print " [ -verbatimcopying ] [ -pkg-site website ]\n"; 206 print " [ -function funcname [ -function funcname ...] ]\n"; 207 print " c source file(s) > outputfile\n"; 208 exit 1; 209} 210 211# read arguments 212if ($#ARGV==-1) { 213 usage(); 214} 215 216$verbose = 0; 217$output_mode = "man"; 218@highlights = @highlights_man; 219$blankline = $blankline_man; 220$modulename = "API Documentation"; 221$sourceversion = strftime "%Y-%m-%d", localtime; 222$function_only = 0; 223while ($ARGV[0] =~ m/^-(.*)/) { 224 $cmd = shift @ARGV; 225 if ($cmd eq "-html") { 226 $output_mode = "html"; 227 @highlights = @highlights_html; 228 $blankline = $blankline_html; 229 } elsif ($cmd eq "-man") { 230 $output_mode = "man"; 231 @highlights = @highlights_man; 232 $blankline = $blankline_man; 233 } elsif ($cmd eq "-tex") { 234 $output_mode = "tex"; 235 @highlights = @highlights_tex; 236 $blankline = $blankline_tex; 237 } elsif ($cmd eq "-texinfo") { 238 $output_mode = "texinfo"; 239 @highlights = @highlights_texinfo; 240 $blankline = $blankline_texinfo; 241 } elsif ($cmd eq "-text") { 242 $output_mode = "text"; 243 @highlights = @highlights_text; 244 $blankline = $blankline_text; 245 } elsif ($cmd eq "-docbook") { 246 $output_mode = "sgml"; 247 @highlights = @highlights_sgml; 248 $blankline = $blankline_sgml; 249 } elsif ($cmd eq "-listfunc") { 250 $output_mode = "listfunc"; 251 } elsif ($cmd eq "-module") { # not needed for sgml, inherits from calling document 252 $modulename = shift @ARGV; 253 } elsif ($cmd eq "-sourceversion") { 254 $sourceversion = shift @ARGV; 255 } elsif ($cmd eq "-include") { 256 $include = shift @ARGV; 257 } elsif ($cmd eq "-includefuncprefix") { 258 $includefuncprefix = 1; 259 } elsif ($cmd eq "-bugsto") { 260 $bugsto = shift @ARGV; 261 } elsif ($cmd eq "-pkg-site") { 262 $pkgsite = shift @ARGV; 263 } elsif ($cmd eq "-copyright") { 264 $copyright = shift @ARGV; 265 } elsif ($cmd eq "-verbatimcopying") { 266 $verbatimcopying = 1; 267 } elsif ($cmd eq "-seeinfo") { 268 $seeinfo = shift @ARGV; 269 } elsif ($cmd eq "-function") { # to only output specific functions 270 $function_only = 1; 271 $function = shift @ARGV; 272 $function_table{$function} = 1; 273 } elsif ($cmd eq "-v") { 274 $verbose = 1; 275 } elsif (($cmd eq "-h") || ($cmd eq "--help")) { 276 usage(); 277 } 278} 279 280## 281# dumps section contents to arrays/hashes intended for that purpose. 282# 283sub dump_section { 284 my $name = shift @_; 285 my $contents = join "\n", @_; 286 287 $name = " $name"; 288 289 if ($name =~ m/$type_constant/) { 290 $name = $1; 291# print STDERR "constant section '$1' = '$contents'\n"; 292 $constants{$name} = $contents; 293 } elsif ($name =~ m/$type_param/) { 294# print STDERR "parameter def '$1' = '$contents'\n"; 295 $name = $1; 296 $parameters{$name} = $contents; 297 } else { 298# print STDERR "other section '$name' = '$contents'\n"; 299 $name =~ tr/ //d; 300 $sections{$name} = $contents; 301 push @sectionlist, $name; 302 } 303} 304 305## 306# output function 307# 308# parameters, a hash. 309# function => "function name" 310# parameterlist => @list of parameters 311# parameters => %parameter descriptions 312# sectionlist => @list of sections 313# sections => %section descriptions 314# 315 316sub just_highlight { 317 my $contents = join "\n", @_; 318 my $line; 319 my $ret = ""; 320 321 foreach $highlight (@highlights) { 322 my ($pattern, $replace) = @$highlight; 323 #print "scanning pattern $pattern ($replace)\n"; 324 $contents =~ s/$pattern/$replace/gees; 325 } 326 foreach $line (split "\n", $contents) { 327 if ($line eq ""){ 328 $ret = $ret . $lineprefix . $blankline; 329 } else { 330 $ret = $ret . $lineprefix . $line; 331 } 332 $ret = $ret . "\n"; 333 } 334 335 return $ret; 336} 337 338sub output_highlight { 339 print (just_highlight (@_)); 340} 341 342# output in texinfo 343sub output_texinfo { 344 my %args = %{$_[0]}; 345 my ($parameter, $section); 346 my $count; 347 348 print "\@subheading ".$args{'function'}."\n"; 349 print "\@anchor{".$args{'function'}."}\n"; 350 print "\@deftypefun {" . $args{'functiontype'} . "} "; 351 print "{".$args{'function'}."} "; 352 print "("; 353 $count = 0; 354 foreach $parameter (@{$args{'parameterlist'}}) { 355 print $args{'parametertypes'}{$parameter}." \@var{".$parameter."}"; 356 if ($count != $#{$args{'parameterlist'}}) { 357 $count++; 358 print ", "; 359 } 360 } 361 print ")\n"; 362 foreach $parameter (@{$args{'parameterlist'}}) { 363 if ($args{'parameters'}{$parameter}) { 364 print "\@var{".$parameter."}: "; 365 output_highlight($args{'parameters'}{$parameter}); 366 print "\n"; 367 } 368 } 369 foreach $section (@{$args{'sectionlist'}}) { 370 $section =~ s/\@//g; 371 print "\n\@strong{$section:} " if $section ne $section_default; 372 $args{'sections'}{$section} =~ s:([{}]):\@$1:gs; 373 output_highlight($args{'sections'}{$section}); 374 } 375 print "\@end deftypefun\n\n"; 376} 377 378sub output_enum_texinfo { 379 my %args = %{$_[0]}; 380 my ($parameter, $section); 381 my $count; 382 my $name = $args{'enum'}; 383 my $param; 384 my $param2; 385 my $sec; 386 my $check; 387 my $type; 388 389 print "\n\@c $name\n"; 390 print "\@table \@code\n"; 391 392 $check=0; 393 foreach $parameter (@{$args{'parameterlist'}}) { 394 $param1 = $parameter; 395 $param1 =~ s/_/_\@-/g; 396 397 $check = 1; 398 print "\@item ".$param1."\n"; 399# print "\n"; 400 401 $param2 = $args{'parameters'}{$parameter}; 402 $out = just_highlight($param2); 403 chomp $out; 404 print $out . "\n"; 405 } 406 print "\@end table\n"; 407} 408 409# output in html 410sub output_html { 411 my %args = %{$_[0]}; 412 my ($parameter, $section); 413 my $count; 414 print "\n\n<a name=\"". $args{'function'} . "\"> </a><h2>Function</h2>\n"; 415 416 print "<i>".$args{'functiontype'}."</i>\n"; 417 print "<b>".$args{'function'}."</b>\n"; 418 print "("; 419 $count = 0; 420 foreach $parameter (@{$args{'parameterlist'}}) { 421 print "<i>".$args{'parametertypes'}{$parameter}."</i> <b>".$parameter."</b>\n"; 422 if ($count != $#{$args{'parameterlist'}}) { 423 $count++; 424 print ", "; 425 } 426 } 427 print ")\n"; 428 429 print "<h3>Arguments</h3>\n"; 430 print "<dl>\n"; 431 foreach $parameter (@{$args{'parameterlist'}}) { 432 print "<dt><i>".$args{'parametertypes'}{$parameter}."</i> <b>".$parameter."</b>\n"; 433 print "<dd>"; 434 output_highlight($args{'parameters'}{$parameter}); 435 } 436 print "</dl>\n"; 437 foreach $section (@{$args{'sectionlist'}}) { 438 print "<h3>$section</h3>\n"; 439 print "<ul>\n"; 440 output_highlight($args{'sections'}{$section}); 441 print "</ul>\n"; 442 } 443 print "<hr>\n"; 444} 445 446# output in tex 447sub output_tex { 448 my %args = %{$_[0]}; 449 my ($parameter, $section); 450 my $count; 451 my $func = $args{'function'}; 452 my $param; 453 my $param2; 454 my $sec; 455 my $check; 456 my $type; 457 458 $func =~ s/_/\\_/g; 459 460 print "\n\n\\begin{function}\n"; 461 print "\\functionTitle{". $func . "}\n"; 462 print "\\index{". $func . "}\n"; 463 464 $type = $args{'functiontype'}; 465 $type =~ s/_/\\_/g; 466 467 print "{\\it ".$type."}\n"; 468 print "{\\bf ".$func."}\n"; 469 print "("; 470 $count = 0; 471 foreach $parameter (@{$args{'parameterlist'}}) { 472 $param = $args{'parametertypes'}{$parameter}; 473 $param2 = $parameter; 474 $param =~ s/_/\\_/g; 475 $param2 =~ s/_/\\_/g; 476 477 print "{\\it ".$param."} {\\bf ".$param2."}"; 478 if ($count != $#{$args{'parameterlist'}}) { 479 $count++; 480 print ", "; 481 } 482 } 483 print ")\n"; 484 485 print "\n\\begin{functionArguments}\n"; 486 487 $check=0; 488 foreach $parameter (@{$args{'parameterlist'}}) { 489 $param1 = $args{'parametertypes'}{$parameter}; 490 $param1 =~ s/_/\\_/g; 491 $param2 = $parameter; 492 $param2 =~ s/_/\\_/g; 493 494 $check = 1; 495 print "\\functionArgument {\\it ".$param1."} {\\bf ".$param2."}: \n"; 496# print "\n"; 497 498 $param3 = $args{'parameters'}{$parameter}; 499 $param3 =~ s/\#([a-zA-Z\_]+)/{\\it $1}/g; 500 $param3 =~ s/\%([a-zA-Z\_]+)/{\\bf $1}/g; 501 502 $out = just_highlight($param3); 503 $out =~ s/_/\\_/g; 504 print $out; 505 } 506 if ($check==0) { 507 print "\\item void\n"; 508 } 509 print "\\end{functionArguments}\n"; 510 511 foreach $section (@{$args{'sectionlist'}}) { 512 $sec = $section; 513 $sec =~ s/_/\\_/g; 514 $sec =~ s/#([a-zA-Z\_]+)/{\\it $1}/g; 515 516 print "\n\\begin{function${sec}}\n"; 517 $out = $args{'sections'}{$section}; 518 519 $out =~ s/\#([a-zA-Z\_]+)/{\\it $1}/g; 520 $out =~ s/\%([a-zA-Z\_]+)/{\\bf $1}/g; 521 $out =~ s/\@([a-zA-Z\_]+)/{\\bf $1}/g; 522 $out =~ s/_/\\_\\-/g; 523 $out =~ s/\$/\\\$/g; 524 $out =~ s/#/\\#/g; 525 $out =~ s/\n\n/\n/g; 526 $out =~ s/\\:/:/g; 527 $out =~ s/\-\>/\$\\rightarrow\$/g; 528 $out =~ s/([0-9]+)\^([0-9]+)/\$\{$1\}\^\{$2\}\$/g; 529 530 print $out; 531 print "\\end{function${sec}}\n"; 532 } 533 print "\\end{function}\n\n"; 534} 535 536sub output_enum_tex { 537 my %args = %{$_[0]}; 538 my ($parameter, $section); 539 my $count; 540 my $name = $args{'enum'}; 541 my $param; 542 my $param2; 543 my $sec; 544 my $check; 545 my $type; 546 547 print "\n\n\\begin{enum}\n"; 548 $name =~ s/_/\\_/g; 549 print "\\enumTitle{". $name . "}\n"; 550 print "\\index{". $name . "}\n"; 551 552 print "\n\\begin{enumList}\n"; 553 554 $check=0; 555 foreach $parameter (@{$args{'parameterlist'}}) { 556 $param1 = $parameter; 557 $param1 =~ s/_/\\_\\-/g; 558 559 $check = 1; 560 print "\\enumElement{".$param1."}{"; 561# print "\n"; 562 563 $param2 = $args{'parameters'}{$parameter}; 564 $param2 =~ s/\#([a-zA-Z\_]+)/{\\it $1}/g; 565 $param2 =~ s/\%([a-zA-Z\_]+)/{\\bf $1}/g; 566 $param2 =~ s/([0-9]+)\^([0-9]+)/\$\{$1\}\^\{$2\}\$/g; 567 $out = just_highlight($param2); 568 $out =~ s/_/\\_/g; 569 chomp $out; 570 print $out . "}\n"; 571 } 572 print "\\end{enumList}\n"; 573 574 print "\\end{enum}\n\n"; 575} 576 577# output in sgml DocBook 578sub output_sgml { 579 my %args = %{$_[0]}; 580 my ($parameter, $section); 581 my $count; 582 my $id; 583 584 $id = $args{'module'}."-".$args{'function'}; 585 $id =~ s/[^A-Za-z0-9]/-/g; 586 587 print "<refentry>\n"; 588 print "<refmeta>\n"; 589 print "<refentrytitle><phrase id=\"$id\">".$args{'function'}."</phrase></refentrytitle>\n"; 590 print "</refmeta>\n"; 591 print "<refnamediv>\n"; 592 print " <refname>".$args{'function'}."</refname>\n"; 593 print " <refpurpose>\n"; 594 print " ".$args{'purpose'}."\n"; 595 print " </refpurpose>\n"; 596 print "</refnamediv>\n"; 597 598 print "<refsynopsisdiv>\n"; 599 print " <title>Synopsis</title>\n"; 600 print " <funcsynopsis>\n"; 601 print " <funcdef>".$args{'functiontype'}." "; 602 print "<function>".$args{'function'}." "; 603 print "</function></funcdef>\n"; 604 605# print "<refsect1>\n"; 606# print " <title>Synopsis</title>\n"; 607# print " <funcsynopsis>\n"; 608# print " <funcdef>".$args{'functiontype'}." "; 609# print "<function>".$args{'function'}." "; 610# print "</function></funcdef>\n"; 611 612 $count = 0; 613 if ($#{$args{'parameterlist'}} >= 0) { 614 foreach $parameter (@{$args{'parameterlist'}}) { 615 print " <paramdef>".$args{'parametertypes'}{$parameter}; 616 print " <parameter>$parameter</parameter></paramdef>\n"; 617 } 618 } else { 619 print " <void>\n"; 620 } 621 print " </funcsynopsis>\n"; 622 print "</refsynopsisdiv>\n"; 623# print "</refsect1>\n"; 624 625 # print parameters 626 print "<refsect1>\n <title>Arguments</title>\n"; 627# print "<para>\nArguments\n"; 628 if ($#{$args{'parameterlist'}} >= 0) { 629 print " <variablelist>\n"; 630 foreach $parameter (@{$args{'parameterlist'}}) { 631 print " <varlistentry>\n <term><parameter>$parameter</parameter></term>\n"; 632 print " <listitem>\n <para>\n"; 633 $lineprefix=" "; 634 output_highlight($args{'parameters'}{$parameter}); 635 print " </para>\n </listitem>\n </varlistentry>\n"; 636 } 637 print " </variablelist>\n"; 638 } else { 639 print " <para>\n None\n </para>\n"; 640 } 641 print "</refsect1>\n"; 642 643 # print out each section 644 $lineprefix=" "; 645 foreach $section (@{$args{'sectionlist'}}) { 646 print "<refsect1>\n <title>$section</title>\n <para>\n"; 647# print "<para>\n$section\n"; 648 if ($section =~ m/EXAMPLE/i) { 649 print "<example><para>\n"; 650 } 651 output_highlight($args{'sections'}{$section}); 652# print "</para>"; 653 if ($section =~ m/EXAMPLE/i) { 654 print "</para></example>\n"; 655 } 656 print " </para>\n</refsect1>\n"; 657 } 658 659 print "\n\n"; 660} 661 662## 663# output in man 664sub output_man { 665 my %args = %{$_[0]}; 666 my ($parameter, $section); 667 my $count; 668 669 print ".\\\" DO NOT MODIFY THIS FILE! It was generated by gdoc.\n"; 670 print ".TH \"$args{'function'}\" 3 \"$args{'sourceversion'}\" \"". $args{'module'} . "\" \"". $args{'module'} . "\"\n"; 671 672 print ".SH NAME\n"; 673 674 print $args{'function'}; 675 if ($args{'purpose'}) { 676 print " \\- " . $args{'purpose'} . "\n"; 677 } else { 678 print " \\- API function\n"; 679 } 680 681 print ".SH SYNOPSIS\n"; 682 print ".B #include <". $args{'include'} . ">\n" 683 if $args{'include'}; 684 print ".B #include <". lc((split /_/, $args{'function'})[0]) . ".h>\n" 685 if $args{'includefuncprefix'}; 686 print ".sp\n"; 687 print ".BI \"".$args{'functiontype'}." ".$args{'function'}."("; 688 $count = 0; 689 foreach $parameter (@{$args{'parameterlist'}}) { 690 print $args{'parametertypes'}{$parameter}." \" ".$parameter." \""; 691 if ($count != $#{$args{'parameterlist'}}) { 692 $count++; 693 print ", "; 694 } 695 } 696 print ");\"\n"; 697 698 print ".SH ARGUMENTS\n"; 699 foreach $parameter (@{$args{'parameterlist'}}) { 700 print ".IP \"".$args{'parametertypes'}{$parameter}." ".$parameter."\" 12\n"; 701 $param = $args{'parameters'}{$parameter}; 702 $param =~ s/-/\\-/g; 703 output_highlight($param); 704 } 705 foreach $section (@{$args{'sectionlist'}}) { 706 print ".SH \"" . uc($section) . "\"\n"; 707 $sec = $args{'sections'}{$section}; 708 $sec =~ s/-/\\-/g; 709 output_highlight($sec); 710 } 711 712 if ($args{'bugsto'}) { 713 print ".SH \"REPORTING BUGS\"\n"; 714 print "Report bugs to <". $args{'bugsto'} . ">.\n"; 715 #print ".br\n"; 716 #print "General guidelines for reporting bugs: https://www.gnu.org/gethelp/\n"; 717 print ".br\n"; 718 if ($args{'pkgsite'}) { 719 print "Home page: " . $args{'pkgsite'} . "\n"; 720 } 721 print "\n"; 722 } 723 724 if ($args{'copyright'}) { 725 print ".SH COPYRIGHT\n"; 726 print "Copyright \\(co ". $args{'copyright'} . ".\n"; 727 if ($args{'verbatimcopying'}) { 728 print ".br\n"; 729 print "Copying and distribution of this file, with or without modification,\n"; 730 print "are permitted in any medium without royalty provided the copyright\n"; 731 print "notice and this notice are preserved.\n"; 732 } 733 } 734 735 if ($args{'seeinfo'}) { 736 print ".SH \"SEE ALSO\"\n"; 737 print "The full documentation for\n"; 738 print ".B " . $args{'module'} . "\n"; 739 print "is maintained as a Texinfo manual.\n"; 740 if ($args{'pkgsite'}) { 741 print "If the /usr/share/doc/". $args{'module'} . "/\n"; 742 print "directory does not contain the HTML form visit\n"; 743 print ".B\n"; 744 print ".IP " . $args{'pkgsite'} . "/manual/\n"; 745 } 746 print ".PP\n"; 747 } 748} 749 750sub output_listfunc { 751 my %args = %{$_[0]}; 752 print $args{'function'} . "\n"; 753} 754 755## 756# output in text 757sub output_text { 758 my %args = %{$_[0]}; 759 my ($parameter, $section); 760 761 print "Function = ".$args{'function'}."\n"; 762 print " return type: ".$args{'functiontype'}."\n\n"; 763 foreach $parameter (@{$args{'parameterlist'}}) { 764 print " ".$args{'parametertypes'}{$parameter}." ".$parameter."\n"; 765 print " -> ".$args{'parameters'}{$parameter}."\n"; 766 } 767 foreach $section (@{$args{'sectionlist'}}) { 768 print " $section:\n"; 769 print " -> "; 770 output_highlight($args{'sections'}{$section}); 771 } 772} 773 774## 775# generic output function - calls the right one based 776# on current output mode. 777sub output_function { 778# output_html(@_); 779 eval "output_".$output_mode."(\@_);"; 780} 781 782sub output_enum { 783 eval "output_enum_".$output_mode."(\@_);"; 784} 785 786 787## 788# takes a function prototype and spits out all the details 789# stored in the global arrays/hsahes. 790sub dump_function { 791 my $prototype = shift @_; 792 793 if ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ || 794 $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ || 795 $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ || 796 $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ || 797 $prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/) { 798 $return_type = $1; 799 $function_name = $2; 800 $args = $3; 801 802 if ($return_type eq 'typedef') { 803 return; 804 } 805 806# print STDERR "ARGS = '$args'\n"; 807 808 foreach $arg (split ',', $args) { 809 # strip leading/trailing spaces 810 $arg =~ s/^\s*//; 811 $arg =~ s/\s*$//; 812# print STDERR "SCAN ARG: '$arg'\n"; 813 @args = split('\s', $arg); 814 815# print STDERR " -> @args\n"; 816 $param = pop @args; 817# print STDERR " -> @args\n"; 818 if ($param =~ m/^(\*+)(.*)/) { 819 $param = $2; 820 push @args, $1; 821 } 822 if ($param =~ m/^(.*)(\[[0-9]*\])$/) { 823 $param = $1; 824 push @args, $2; 825 } 826# print STDERR " :> @args\n"; 827 $type = join " ", @args; 828 829 if ((!defined($parameters{$param}) || $parameters{$param} eq "") && $param ne "void") { 830 $parameters{$param} = "-- undescribed --"; 831 print STDERR "error: $lineno: Function parameter '$param' not described in '$function_name'\n"; 832 exit 1; 833 } 834 835 push @parameterlist, $param; 836 $parametertypes{$param} = $type; 837 838# print STDERR "param = '$param', type = '$type'\n"; 839 } 840 } else { 841 print STDERR "error: $lineno: Cannot understand prototype: '$prototype'\n"; 842 exit 1; 843 } 844 845 if ($function_only==0 || defined($function_table{$function_name})) { 846 $function_found=1; 847 output_function({'function' => $function_name, 848 'module' => $modulename, 849 'sourceversion' => $sourceversion, 850 'include' => $include, 851 'includefuncprefix' => $includefuncprefix, 852 'bugsto' => $bugsto, 853 'pkgsite' => $pkgsite, 854 'copyright' => $copyright, 855 'verbatimcopying' => $verbatimcopying, 856 'seeinfo' => $seeinfo, 857 'functiontype' => $return_type, 858 'parameterlist' => \@parameterlist, 859 'parameters' => \%parameters, 860 'parametertypes' => \%parametertypes, 861 'sectionlist' => \@sectionlist, 862 'sections' => \%sections, 863 'purpose' => $function_purpose 864 }); 865 } 866} 867 868sub dump_enum { 869 my $prototype = shift @_; 870 871 if (($prototype =~ m/^\s*typedef\s+enum\s*[a-zA-Z0-9_~:]*\s*\{([\-a-zA-Z0-9_~=,:\s\(\)\<]+)\s*\}\s*([a-zA-Z0-9_]+);.*/)) { 872# || $prototype =~ m/^\s*enum\s+([a-zA-Z0-9_~:]+).*/) { 873 $args = $1; 874 $name = $2; 875 876 foreach $arg (split ',', $args) { 877 # strip leading/trailing spaces 878 $arg =~ s/^\s*//; 879 $arg =~ s/\s*$//; 880 $arg =~ s/([A-Za-z0-9_]+)\s*=.*/$1/g; 881# print STDERR "SCAN ARG: '$arg'\n"; 882 883 next if $arg eq ''; 884 if ((!defined($parameters{$arg}) || $parameters{$arg} eq "")) { 885 $parameters{$arg} = "-- undescribed --"; 886 print STDERR "warning: $lineno: Enumeration parameter '$arg' not described in '$name'\n"; 887 } 888 889 push @parameterlist, $arg; 890 891# print STDERR "param = '$arg'\n"; 892 } 893 } else { 894# print STDERR "warning: $lineno: Cannot understand enumeration: '$prototype'\n"; 895 return; 896 } 897 898 output_enum({'enum' => $name, 899 'module' => $modulename, 900 'sourceversion' => $sourceversion, 901 'include' => $include, 902 'includefuncprefix' => $includefuncprefix, 903 'bugsto' => $bugsto, 904 'pkgsite' => $pkgsite, 905 'copyright' => $copyright, 906 'verbatimcopying' => $verbatimcopying, 907 'seeinfo' => $seeinfo, 908 'functiontype' => $return_type, 909 'parameterlist' => \@parameterlist, 910 'parameters' => \%parameters, 911 'parametertypes' => \%parametertypes, 912 'sectionlist' => \@sectionlist, 913 'sections' => \%sections, 914 'purpose' => $function_purpose 915 }); 916} 917 918###################################################################### 919# main 920# states 921# 0 - normal code 922# 1 - looking for function name 923# 2 - scanning field start. 924# 3 - scanning prototype. 925$state = 0; 926$section = ""; 927 928$doc_special = "\@\%\$\#"; 929 930$doc_start = "^/\\*\\*\$"; 931$doc_end = "\\*/"; 932$doc_com = "\\s*\\*\\s*"; 933$doc_func = $doc_com."(\\w+):?"; 934$doc_sect = $doc_com."([".$doc_special."[:upper:]][\\w]+):\\s*(.*)"; 935$doc_content = $doc_com."(.*)"; 936 937%constants = (); 938%parameters = (); 939@parameterlist = (); 940%sections = (); 941@sectionlist = (); 942 943$contents = ""; 944$section_default = "Description"; # default section 945$section = $section_default; 946$enum = 0; 947 948$lineno = 0; 949 950foreach $file (@ARGV) { 951 if (!open(IN,"<$file")) { 952 print STDERR "Error: Cannot open file $file\n"; 953 next; 954 } 955 while ($line = <IN>) { 956 $lineno++; 957 958 if ($state == 0) { 959 if ($line =~ /$doc_start/o) { 960 $state = 1; # next line is always the function name 961# print STDERR "XXX: start of doc comment\n"; 962 } 963 } elsif ($state == 1) { # this line is the function name (always) 964 if ($line =~ /$doc_func/o) { 965 $function = $1; 966 $state = 2; 967# print STDERR "XXX: start of doc comment, looking for prototype\n"; 968 969 if ($line =~ /-\s*(.*)/) { 970 $function_purpose = $1; 971 } else { 972 $function_purpose = ""; 973 } 974 if ($verbose) { 975 print STDERR "Info($lineno): Scanning doc for $function\n"; 976 } 977 } else { 978 print STDERR "warning: $lineno: Cannot understand $_ on line $lineno", 979 " - I thought it was a doc line\n"; 980 $state = 0; 981 } 982 } elsif ($state == 2) { # look for head: lines, and include content 983 if ($line =~ /$doc_sect/o) { 984 $newsection = $1; 985 $newcontents = $2; 986 987 if ($contents ne '') { 988 dump_section($section, $contents); 989 $section = $section_default; 990 } 991 992 $contents = $newcontents; 993 if ($contents ne "") { 994 $contents .= "\n"; 995 } 996 $section = $newsection; 997 } elsif ($line =~ /$doc_end/) { 998 999 if ($contents ne "") { 1000 dump_section($section, $contents); 1001 $section = $section_default; 1002 $contents = ""; 1003 } 1004 1005 $prototype = ''; 1006 $state = 3; 1007 } elsif ($line =~ /$doc_content/) { 1008 # miguel-style comment kludge, look for blank lines after 1009 # @parameter line to signify start of description 1010 if ($1 eq '' && $section =~ m/^@/) { 1011 dump_section($section, $contents); 1012 $section = $section_default; 1013 $contents = ""; 1014 } else { 1015 $contents .= $1."\n"; 1016 } 1017 } else { 1018 # i don't know - bad line? ignore. 1019 #print STDERR "warning: $lineno: Bad line: $_"; 1020 } 1021 } elsif ($state == 3) { # scanning for function { (end of prototype) 1022 if ($line =~ /([a-zA-Z\s]+)enum(.*)$/) { 1023 $enum = 1; 1024 } 1025 1026 if ($line =~ m#\s*/\*\s+MACDOC\s*#io) { 1027 # do nothing 1028 } 1029 elsif ($enum == 1 && $line =~ /(\s*\{).*/) { 1030 $prototype = "typedef enum {"; 1031 } 1032 elsif ($line =~ /([^\{]*)/) { 1033 $prototype .= $1; 1034 } 1035 1036 if ($enum == 0 && $line =~ /;/) { 1037 $prototype =~ s@/\*.*?\*/@@gos; # strip comments. 1038 $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's. 1039 $prototype =~ s@^ +@@gos; # strip leading spaces 1040 1041 dump_function($prototype); 1042 1043 $function = ""; 1044 %constants = (); 1045 %parameters = (); 1046 %parametertypes = (); 1047 @parameterlist = (); 1048 %sections = (); 1049 @sectionlist = (); 1050 $prototype = ""; 1051 $enum = 0; 1052 1053 $state = 0; 1054 } 1055 elsif ($enum == 1 && $line =~ /\}/) { 1056 $prototype =~ s@/\*.*?\*/@@gos; # strip comments. 1057 $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's. 1058 $prototype =~ s@^ +@@gos; # strip leading spaces 1059 1060 dump_enum($prototype); 1061 1062 $function = ""; 1063 %constants = (); 1064 %parameters = (); 1065 %parametertypes = (); 1066 @parameterlist = (); 1067 %sections = (); 1068 @sectionlist = (); 1069 $prototype = ""; 1070 $enum = 0; 1071 1072 $state = 0; 1073 } 1074 1075 } 1076 } 1077} 1078 1079if ($function_only != 0 && $function_found == 0) { 1080 print STDERR "error: could not find the expected function\n"; 1081 exit 1; 1082} 1083