1#!/usr/bin/perl -w
2
3use strict;
4
5## Copyright (C) 2015  Intel Corporation                         ##
6#                                                                ##
7## This software falls under the GNU General Public License.     ##
8## Please read the COPYING file for more information             ##
9#
10#
11# This software reads a XML file and a list of valid interal
12# references to replace Docbook tags with links.
13#
14# The list of "valid internal references" must be one-per-line in the following format:
15#      API-struct-foo
16#      API-enum-bar
17#      API-my-function
18#
19# The software walks over the XML file looking for xml tags representing possible references
20# to the Document. Each reference will be cross checked against the "Valid Internal Reference" list. If
21# the referece is found it replaces its content by a <link> tag.
22#
23# usage:
24# kernel-doc-xml-ref -db filename
25#		     xml filename > outputfile
26
27# read arguments
28if ($#ARGV != 2) {
29	usage();
30}
31
32#Holds the database filename
33my $databasefile;
34my @database;
35
36#holds the inputfile
37my $inputfile;
38my $errors = 0;
39
40my %highlights = (
41	"<function>(.*?)</function>",
42	    "\"<function>\" . convert_function(\$1, \$line) . \"</function>\"",
43	"<structname>(.*?)</structname>",
44	    "\"<structname>\" . convert_struct(\$1) . \"</structname>\"",
45	"<funcdef>(.*?)<function>(.*?)</function></funcdef>",
46	    "\"<funcdef>\" . convert_param(\$1) . \"<function>\$2</function></funcdef>\"",
47	"<paramdef>(.*?)<parameter>(.*?)</parameter></paramdef>",
48	    "\"<paramdef>\" . convert_param(\$1) . \"<parameter>\$2</parameter></paramdef>\"");
49
50while($ARGV[0] =~ m/^-(.*)/) {
51	my $cmd = shift @ARGV;
52	if ($cmd eq "-db") {
53		$databasefile = shift @ARGV
54	} else {
55		usage();
56	}
57}
58$inputfile = shift @ARGV;
59
60sub open_database {
61	open (my $handle, '<', $databasefile) or die "Cannot open $databasefile";
62	chomp(my @lines = <$handle>);
63	close $handle;
64
65	@database = @lines;
66}
67
68sub process_file {
69	open_database();
70
71	my $dohighlight;
72	foreach my $pattern (keys %highlights) {
73		$dohighlight .=  "\$line =~ s:$pattern:$highlights{$pattern}:eg;\n";
74	}
75
76	open(FILE, $inputfile) or die("Could not open $inputfile") or die ("Cannot open $inputfile");
77	foreach my $line (<FILE>)  {
78		eval $dohighlight;
79		print $line;
80	}
81}
82
83sub trim($_)
84{
85	my $str = $_[0];
86	$str =~ s/^\s+|\s+$//g;
87	return $str
88}
89
90sub has_key_defined($_)
91{
92	if ( grep( /^$_[0]$/, @database)) {
93		return 1;
94	}
95	return 0;
96}
97
98# Gets a <function> content and add it a hyperlink if possible.
99sub convert_function($_)
100{
101	my $arg = $_[0];
102	my $key = $_[0];
103
104	my $line = $_[1];
105
106	$key = trim($key);
107
108	$key =~ s/[^A-Za-z0-9]/-/g;
109	$key = "API-" . $key;
110
111	# We shouldn't add links to <funcdef> prototype
112	if (!has_key_defined($key) || $line =~ m/\s+<funcdef/i) {
113		return $arg;
114	}
115
116	my $head = $arg;
117	my $tail = "";
118	if ($arg =~ /(.*?)( ?)$/) {
119		$head = $1;
120		$tail = $2;
121	}
122	return "<link linkend=\"$key\">$head</link>$tail";
123}
124
125# Converting a struct text to link
126sub convert_struct($_)
127{
128	my $arg = $_[0];
129	my $key = $_[0];
130	$key =~ s/(struct )?(\w)/$2/g;
131	$key =~ s/[^A-Za-z0-9]/-/g;
132	$key = "API-struct-" . $key;
133
134	if (!has_key_defined($key)) {
135		return $arg;
136	}
137
138	my ($head, $tail) = split_pointer($arg);
139	return "<link linkend=\"$key\">$head</link>$tail";
140}
141
142# Identify "object *" elements
143sub split_pointer($_)
144{
145	my $arg = $_[0];
146	if ($arg =~ /(.*?)( ?\* ?)/) {
147		return ($1, $2);
148	}
149	return ($arg, "");
150}
151
152sub convert_param($_)
153{
154	my $type = $_[0];
155	my $keyname = convert_key_name($type);
156
157	if (!has_key_defined($keyname)) {
158		return $type;
159	}
160
161	my ($head, $tail) = split_pointer($type);
162	return "<link linkend=\"$keyname\">$head</link>$tail";
163
164}
165
166# DocBook links are in the API-<TYPE>-<STRUCT-NAME> format
167# This method gets an element and returns a valid DocBook reference for it.
168sub convert_key_name($_)
169{
170	#Pattern $2 is optional and might be uninitialized
171	no warnings 'uninitialized';
172
173	my $str = $_[0];
174	$str =~ s/(const|static)? ?(struct)? ?([a-zA-Z0-9_]+) ?(\*|&)?/$2 $3/g ;
175
176	# trim
177	$str =~ s/^\s+|\s+$//g;
178
179	# spaces and _ to -
180	$str =~ s/[^A-Za-z0-9]/-/g;
181
182	return "API-" . $str;
183}
184
185sub usage {
186	print "Usage: $0 -db database filename\n";
187	print "         xml source file(s) > outputfile\n";
188	exit 1;
189}
190
191# starting point
192process_file();
193
194if ($errors) {
195	print STDERR "$errors errors\n";
196}
197
198exit($errors);
199