3 #############################################################################
4 # Script : migratetmpl.pl
5 # Description : Read template files and reformate them as source code
8 # Example : cd glib/docs/reference/glib
9 # migratetmpl.pl --module=glib --source-dir=../../../glib
10 # cd glib/docs/reference/gmodule
11 # migratetmpl.pl --module=glib --source-dir=../../../glib
13 # Todo : - remove docs from tmpl files if there are comments in the src
14 # - allow running for only 1 tmpl file (= one section)
15 #############################################################################
19 use Parse
::ExuberantCTags
;
23 # name of documentation module
30 my %optctl = ('module' => \
$MODULE,
31 'tmpl-dir' => \
$TMPL_DIR,
32 'extra-source-dir' => \
$EXTRA_SRC_DIR,
33 'source-dir' => \
$SRC_DIR,
34 'help' => \
$PRINT_HELP);
35 GetOptions
(\
%optctl, "module=s", "tmpl-dir:s", "source-dir:s", "help");
45 --module=MODULE_NAME Name of the doc module being parsed
46 --tmpl-dir=DIRNAME Directory in which template files may be found
47 --extra-source-dir=DIRNAME Directory where to put the generated sources
48 --source-dir=DIRNAME Directory of existing sources
49 --help Print this help
56 if (! -e
"$ROOT_DIR/$MODULE-sections.txt") {
57 die "No $ROOT_DIR/$MODULE-sections.txt file found, please run this from doc-dir";
60 # All the files are read from subdirectories beneath here.
61 $TMPL_DIR = $TMPL_DIR ?
$TMPL_DIR : "$ROOT_DIR/tmpl";
62 $EXTRA_SRC_DIR = $EXTRA_SRC_DIR ?
$EXTRA_SRC_DIR : "$ROOT_DIR/src";
64 # These global hashes store the existing documentation.
68 # These global hashes store declaration info keyed on a symbol name.
76 `cd $SRC_DIR; make ctags`;
77 $tags = Parse
::ExuberantCTags
->new("$SRC_DIR/tags");
80 # Create the src output directory if it doens't exist.
81 if (! -e
$EXTRA_SRC_DIR) {
82 mkdir ("$EXTRA_SRC_DIR", 0777)
83 || die "Can't create directory: $EXTRA_SRC_DIR";
86 # now process the files
87 &Convert
("$ROOT_DIR/$MODULE-sections.txt");
90 #############################################################################
92 # Description : Parse the section file and convert each template back to source
94 # Arguments : $file - the section file that lists all templates
95 #############################################################################
99 #print "Reading: $file\n";
101 || die "Can't open $file: $!";
108 } elsif (m/^<FILE>(.*)<\/FILE
>/) {
110 if (&ReadTemplateFile
("$TMPL_DIR/$filename")) {
111 &OutputSourceFile
("$EXTRA_SRC_DIR/$filename",$filename);
119 #############################################################################
120 # Function : ReadTemplateFile
121 # Description : This reads in the manually-edited documentation file
122 # corresponding to the file currently being created, so we can
123 # insert the documentation at the appropriate places.
124 # It outputs %SymbolTypes, %SymbolDocs and %SymbolParams, which
125 # is a hash of arrays.
126 # NOTE: This function is duplicated in gtkdoc-mktmpl (but
127 # slightly different).
128 # Arguments : $docsfile - the template file to read in.
129 #############################################################################
130 sub ReadTemplateFile
{
133 my $template = "$docsfile.sgml";
134 if (! -f
$template) {
135 #print "File doesn't exist: $template\n";
138 #print "Reading $template\n";
140 # start with empty hashes, we merge the source comment for each file
146 my $current_type = ""; # Type of symbol being read.
147 my $current_symbol = ""; # Name of symbol being read.
148 my $symbol_doc = ""; # Description of symbol being read.
149 my @params; # Parameter names and descriptions of current
150 # function/macro/function typedef.
151 my $current_param = -1; # Index of parameter currently being read.
152 # Note that the param array contains pairs
153 # of param name & description.
154 my $in_unused_params = 0; # True if we are reading in the unused params.
155 my $in_deprecated = 0;
157 my $in_stability = 0;
159 open (DOCS
, "$template")
160 || die "Can't open $template: $!";
162 if (m/^<!-- ##### ([A-Z_]+) (\S+) ##### -->/) {
165 if ($symbol eq "Title"
166 || $symbol eq "Short_Description"
167 || $symbol eq "Long_Description"
168 || $symbol eq "See_Also"
169 || $symbol eq "Stability_Level"
170 || $symbol eq "Include") {
172 $symbol = $docsfile . ":" . $symbol;
175 #print "Found symbol: $symbol\n";
177 # Store previous symbol, but remove any trailing blank lines.
178 if ($current_symbol ne "") {
179 $symbol_doc =~ s/\s+$//;
180 $SymbolTypes{$current_symbol} = $current_type;
181 $SymbolDocs{$current_symbol} = $symbol_doc;
183 # Check that the stability level is valid.
184 if ($StabilityLevel{$current_symbol}) {
185 $StabilityLevel{$current_symbol} = &ParseStabilityLevel
($StabilityLevel{$current_symbol}, $template, $., "Stability level for $current_symbol");
188 if ($current_param >= 0) {
189 $SymbolParams{$current_symbol} = [ @params ];
191 # Delete any existing params in case we are overriding a
192 # previously read template.
193 delete $SymbolParams{$current_symbol};
196 $current_type = $type;
197 $current_symbol = $symbol;
199 $in_unused_params = 0;
206 } elsif (m/^<!-- # Unused Parameters # -->/) {
207 #print "DEBUG: Found unused parameters\n";
208 $in_unused_params = 1;
211 } elsif ($in_unused_params) {
212 #print "DEBUG: Skipping unused param: $_";
216 # Check if param found. Need to handle "..." and "format...".
217 if (s/^\@([\w\.]+):\040?//) {
219 # Allow variations of 'Returns'
220 if ($param_name =~ m/^[Rr]eturns?$/) {
221 $param_name = "Returns";
223 #print "Found param for symbol $current_symbol : '$param_name'= '$_'\n";
225 if ($param_name eq "Deprecated") {
227 $Deprecated{$current_symbol} = $_;
228 } elsif ($param_name eq "Since") {
230 $Since{$current_symbol} = $_;
231 } elsif ($param_name eq "Stability") {
233 $StabilityLevel{$current_symbol} = $_;
235 push (@params, $param_name);
240 if ($in_deprecated) {
241 $Deprecated{$current_symbol} .= $_;
242 } elsif ($in_since) {
243 $Since{$current_symbol} .= $_;
244 } elsif ($in_stability) {
245 $StabilityLevel{$current_symbol} .= $_;
246 } elsif ($current_param >= 0) {
247 $params[$current_param] .= $_;
255 # Remember to finish the current symbol doccs.
256 if ($current_symbol ne "") {
257 $symbol_doc =~ s/\s+$//;
258 $SymbolTypes{$current_symbol} = $current_type;
259 $SymbolDocs{$current_symbol} = $symbol_doc;
261 # Check that the stability level is valid.
262 if ($StabilityLevel{$current_symbol}) {
263 $StabilityLevel{$current_symbol} = &ParseStabilityLevel
($StabilityLevel{$current_symbol}, $template, $., "Stability level for $current_symbol");
266 if ($current_param >= 0) {
267 $SymbolParams{$current_symbol} = [ @params ];
269 # Delete any existing params in case we are overriding a
270 # previously read template.
271 delete $SymbolParams{$current_symbol};
279 #############################################################################
280 # Function : OutputSourceFile
281 # Description : Format the source comments for one file.
282 # Arguments : $docsfile - the basename for the output file
283 # $file - base filename
284 #############################################################################
285 sub OutputSourceFile
{
286 my ($docsfile,$file) = @_;
288 my $source = "$docsfile.c";
290 open (OUTPUT
, ">$source")
291 || die "Can't create $source";
293 # output section docs
294 my ($title, $short_desc, $long_desc, $see_also, $stability);
296 if (defined ($SymbolDocs{"$TMPL_DIR/$file:Title"})) {
297 $title = $SymbolDocs{"$TMPL_DIR/$file:Title"};
298 delete $SymbolDocs{"$TMPL_DIR/$file:Title"};
300 if (defined ($SymbolDocs{"$TMPL_DIR/$file:Short_Description"})) {
301 $short_desc = $SymbolDocs{"$TMPL_DIR/$file:Short_Description"};
302 delete $SymbolDocs{"$TMPL_DIR/$file:Short_Description"};
304 if (defined ($SymbolDocs{"$TMPL_DIR/$file:Long_Description"})) {
305 $long_desc = $SymbolDocs{"$TMPL_DIR/$file:Long_Description"};
306 $long_desc = &ConvertMarkup
($long_desc);
307 $long_desc = &ConvertComments
($long_desc);
308 delete $SymbolDocs{"$TMPL_DIR/$file:Long_Description"};
310 if (defined ($SymbolDocs{"$TMPL_DIR/$file:See_Also"})) {
311 $see_also = $SymbolDocs{"$TMPL_DIR/$file:See_Also"};
312 $see_also = &ConvertMarkup
($see_also);
313 delete $SymbolDocs{"$TMPL_DIR/$file:See_Also"};
315 if (defined ($SymbolDocs{"$TMPL_DIR/$file:Stability_Level"})) {
316 $stability = $SymbolDocs{"$TMPL_DIR/$file:Stability_Level"};
317 delete $SymbolDocs{"$TMPL_DIR/$file:Stability_Level"};
320 print (OUTPUT
<<EOF);
324 if (defined($short_desc) && ($short_desc ne "")) {
325 print (OUTPUT
" * \@Short_description: $short_desc\n");
327 if (defined($title) && ($title ne "")) {
328 print (OUTPUT
" * \@Title: $title\n");
330 if (defined($see_also) && ($see_also ne "")) {
332 my $first="\@See_also:";
333 for $line (split (/\n/, $see_also)) {
334 print (OUTPUT
" * $first$line\n");
338 if (defined($stability) && ($stability ne "")) {
339 print (OUTPUT
" * \@Stability: $stability\n");
341 if (defined($long_desc) && ($long_desc ne "")) {
343 print (OUTPUT
" * \n");
344 for $line (split (/\n/, $long_desc)) {
345 print (OUTPUT
" * $line\n");
348 print (OUTPUT
<<EOF);
358 foreach $symbol (keys (%SymbolDocs)) {
359 $docblob=&GetSymbolDoc
($symbol);
360 next if (!defined $docblob);
363 # if we have tags, check if we find the symbol location
365 my $tag = $tags->findTag($symbol, ignore_case
=> 0, partial
=> 0);
368 my $srcfile=$tag->{file
};
370 if (defined $tag->{addressLineNumber
}) {
371 $srcline=$tag->{addressLineNumber
}
373 if (-e
"$SRC_DIR/$srcfile") {
377 my $source = "$SRC_DIR/$srcfile";
379 open (SRC
, "$source");
383 if (!defined $srcline) {
384 my $re = $tag->{addressPattern
};
387 $re =~ s/([*()])/\\$1/g;
391 if ($lines[$_] =~ $re) {
396 if (!defined $srcline) {
397 print "no line found for : $symbol in $srcfile using regexp: ", $re, "\n";
401 if (defined $srcline) {
402 my $offset = $srcline-1;
404 if ($SymbolTypes{$symbol} eq "FUNCTION") {
405 # go one up to skip return type
406 # FIXME: check if the $symbol starts at the begin of the line
407 # if ($lines[$srcline] =~ m/^$symbol/)
411 splice @lines,$offset,$#lines-$offset,($docblob,@lines[$offset..($#lines+-1)]);
413 # patch file and overwrite
414 open (SRC
, ">$source");
418 # rebuild and reread ctags
419 `cd $SRC_DIR; make ctags`;
420 $tags = Parse
::ExuberantCTags
->new("$SRC_DIR/tags");
425 print "no source found for : $symbol\n";
429 print "no tag found for : $symbol\n";
433 print (OUTPUT
$docblob."\n\n");
441 #############################################################################
442 # Function : GetSymbolDoc
443 # Description : Format the docs for one symbol
444 # Arguments : $symbol - the symbol
445 #############################################################################
450 my ($params, $long_desc, $stability, $deprecated, $since, $returns);
453 if (defined ($SymbolParams{$symbol})) {
454 $params = $SymbolParams{$symbol}
456 if (defined ($StabilityLevel{$symbol})) {
457 $stability = $StabilityLevel{$symbol};
459 if (defined ($Deprecated{$symbol})) {
460 $deprecated = $Deprecated{$symbol};
461 $deprecated = &FormatMultiline
($deprecated);
463 if (defined ($Since{$symbol})) {
464 ($since, undef) = split (/\n/,$Since{$symbol});
466 $long_desc = $SymbolDocs{$symbol};
467 $long_desc = &ConvertMarkup
($long_desc);
468 $long_desc = &ConvertComments
($long_desc);
474 if (defined($params)) {
476 for ($j = 0; $j <= $#$params; $j += 2) {
477 my $param_name = $$params[$j];
478 my $param_desc = $$params[$j+1];
480 $param_desc = &FormatMultiline
($param_desc);
482 if ($param_desc ne "\n") {
486 if ($param_name eq "Varargs") {
490 if ($param_name eq "Returns") {
491 $returns = $param_desc;
494 $str = $str." * \@$param_name: $param_desc";
498 if (defined($long_desc) && ($long_desc ne "")) {
501 for $line (split (/\n/, $long_desc)) {
502 $str = $str." * $line\n";
507 if (defined($stability) && ($stability ne "")) {
508 $str = $str.$spacer." * Stability: $stability\n";
512 if (defined($deprecated) && ($deprecated ne "")) {
513 $str = $str.$spacer." * Deprecated: $deprecated";
517 if (defined($since) && ($since ne "")) {
518 $str = $str.$spacer." * Since: $since\n";
522 if (defined($returns) && ($returns ne "")) {
523 $str = $str.$spacer." * Returns: $returns\n";
530 #print "empty docs for $symbol\n";
536 #############################################################################
537 # Function : ConvertMarkup
538 # Description : Convert para tags to newlines and character entities back
539 # Arguments : $istr - string to convert
540 #############################################################################
546 for $line (split (/\n/, $istr)) {
547 if ($line =~ m/^\s*<para>\s*$/) {
550 } elsif ($line =~ m/^\s*<\/para
>\s
*$/) {
554 # convert character entities back.
555 $line =~ s/&/&/g;
556 $line =~ s/#/#/g;
566 #############################################################################
567 # Function : ConvertComments
568 # Description : Convert single line c comments to c++ comments
569 # Arguments : $istr - string to convert
570 #############################################################################
571 sub ConvertComments
{
576 for $line (split (/\n/, $istr)) {
577 if ($line =~ m
#/\*.*\*/#) {
581 $line =~ s
#/\*#/<!---->\*#;
582 $line =~ s
#\*/#\*<!---->/#;
589 #############################################################################
590 # Function : FormatMultiline
591 # Description : Format multiline text and remove blank lines
592 # Arguments : $istr - string to convert
593 #############################################################################
594 sub FormatMultiline
{
599 for $line (split (/\n/, $istr)) {
601 $line =~ m/\s*(.*)\s*/g;