#!/usr/bin/perl -w use strict; ## Copyright (C) 2015 Intel Corporation ## # ## ## This software falls under the GNU General Public License. ## ## Please read the COPYING file for more information ## # # # This software reads a XML file and a list of valid interal # references to replace Docbook tags with links. # # The list of "valid internal references" must be one-per-line in the following format: # API-struct-foo # API-enum-bar # API-my-function # # The software walks over the XML file looking for xml tags representing possible references # to the Document. Each reference will be cross checked against the "Valid Internal Reference" list. If # the referece is found it replaces its content by a <link> tag. # # usage: # kernel-doc-xml-ref -db filename # xml filename > outputfile # read arguments if ($#ARGV != 2) { usage(); } #Holds the database filename my $databasefile; my @database; #holds the inputfile my $inputfile; my $errors = 0; my %highlights = ( "<function>(.*?)</function>", "\"<function>\" . convert_function(\$1, \$line) . \"</function>\"", "<structname>(.*?)</structname>", "\"<structname>\" . convert_struct(\$1) . \"</structname>\"", "<funcdef>(.*?)<function>(.*?)</function></funcdef>", "\"<funcdef>\" . convert_param(\$1) . \"<function>\$2</function></funcdef>\"", "<paramdef>(.*?)<parameter>(.*?)</parameter></paramdef>", "\"<paramdef>\" . convert_param(\$1) . \"<parameter>\$2</parameter></paramdef>\""); while($ARGV[0] =~ m/^-(.*)/) { my $cmd = shift @ARGV; if ($cmd eq "-db") { $databasefile = shift @ARGV } else { usage(); } } $inputfile = shift @ARGV; sub open_database { open (my $handle, '<', $databasefile) or die "Cannot open $databasefile"; chomp(my @lines = <$handle>); close $handle; @database = @lines; } sub process_file { open_database(); my $dohighlight; foreach my $pattern (keys %highlights) { $dohighlight .= "\$line =~ s:$pattern:$highlights{$pattern}:eg;\n"; } open(FILE, $inputfile) or die("Could not open $inputfile") or die ("Cannot open $inputfile"); foreach my $line (<FILE>) { eval $dohighlight; print $line; } } sub trim($_) { my $str = $_[0]; $str =~ s/^\s+|\s+$//g; return $str } sub has_key_defined($_) { if ( grep( /^$_[0]$/, @database)) { return 1; } return 0; } # Gets a <function> content and add it a hyperlink if possible. sub convert_function($_) { my $arg = $_[0]; my $key = $_[0]; my $line = $_[1]; $key = trim($key); $key =~ s/[^A-Za-z0-9]/-/g; $key = "API-" . $key; # We shouldn't add links to <funcdef> prototype if (!has_key_defined($key) || $line =~ m/\s+<funcdef/i) { return $arg; } my $head = $arg; my $tail = ""; if ($arg =~ /(.*?)( ?)$/) { $head = $1; $tail = $2; } return "<link linkend=\"$key\">$head</link>$tail"; } # Converting a struct text to link sub convert_struct($_) { my $arg = $_[0]; my $key = $_[0]; $key =~ s/(struct )?(\w)/$2/g; $key =~ s/[^A-Za-z0-9]/-/g; $key = "API-struct-" . $key; if (!has_key_defined($key)) { return $arg; } my ($head, $tail) = split_pointer($arg); return "<link linkend=\"$key\">$head</link>$tail"; } # Identify "object *" elements sub split_pointer($_) { my $arg = $_[0]; if ($arg =~ /(.*?)( ?\* ?)/) { return ($1, $2); } return ($arg, ""); } sub convert_param($_) { my $type = $_[0]; my $keyname = convert_key_name($type); if (!has_key_defined($keyname)) { return $type; } my ($head, $tail) = split_pointer($type); return "<link linkend=\"$keyname\">$head</link>$tail"; } # DocBook links are in the API-<TYPE>-<STRUCT-NAME> format # This method gets an element and returns a valid DocBook reference for it. sub convert_key_name($_) { #Pattern $2 is optional and might be uninitialized no warnings 'uninitialized'; my $str = $_[0]; $str =~ s/(const|static)? ?(struct)? ?([a-zA-Z0-9_]+) ?(\*|&)?/$2 $3/g ; # trim $str =~ s/^\s+|\s+$//g; # spaces and _ to - $str =~ s/[^A-Za-z0-9]/-/g; return "API-" . $str; } sub usage { print "Usage: $0 -db database filename\n"; print " xml source file(s) > outputfile\n"; exit 1; } # starting point process_file(); if ($errors) { print STDERR "$errors errors\n"; } exit($errors);