ident 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. #!/usr/bin/perl
  2. # $Id: ident,v 1.8 2006/12/07 04:59:38 reed%reedloden.com Exp $
  3. # ident -- Look up identifiers
  4. #
  5. # Arne Georg Gleditsch <argggh@ifi.uio.no>
  6. # Per Kristian Gjermshus <pergj@ifi.uio.no>
  7. #
  8. #
  9. # This program is free software; you can redistribute it and/or modify
  10. # it under the terms of the GNU General Public License as published by
  11. # the Free Software Foundation; either version 2 of the License, or
  12. # (at your option) any later version.
  13. #
  14. # This program is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. # GNU General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU General Public License
  20. # along with this program; if not, write to the Free Software
  21. # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22. ######################################################################
  23. use lib 'lib';
  24. use Local;
  25. use LXR::Common;
  26. use LXR::Config;
  27. use DB_File;
  28. @tyy= (
  29. ('I', 'interface'),
  30. ('C', 'class'), # C++
  31. ('c', '(forwarded) class'), # C++
  32. ('M', 'preprocessor macro'),
  33. ('F', 'function'),
  34. ('f', 'function prototype'),
  35. ('T', 'type'),
  36. ('S', 'struct type'),
  37. ('E', 'enum type'),
  38. ('U', 'union type'),
  39. ('V', 'variable'),
  40. ('R', 'reference'),
  41. );
  42. %ty = @tyy;
  43. sub list_links
  44. {
  45. my ($t, $fnam, $concise, $lines) = @_;
  46. @fpos = sort { $a <=> $b } split(/,/, $lines);
  47. if ($concise && /:/ !~ $lines) {
  48. print("<li>", &fileref("$fnam", "/$fnam"),
  49. ", ",$#fpos+1,' time'.($#fpos?'s':'')."\n");
  50. } else {
  51. print("<li>". &fileref("$fnam", "/$fnam"));
  52. unless ($concise) {
  53. my $blamelines = $lines;
  54. $blamelines =~ s/:[^,]*//g;
  55. print(&blamerefs($fnam, $blamelines));
  56. }
  57. my $closefilereader;
  58. my %filedesc = (line => 0, data => '');
  59. if (open FILEREADER, '<', $Path->{'realf'}) {
  60. $closefilereader = 1;
  61. $filedesc{'line'} = 0;
  62. $filedesc{'data'} = '';
  63. } else {
  64. print "<!-- couldn't open $fnam -->";
  65. }
  66. sub getline {
  67. my ($filedesc, $lineno) = @_;
  68. my ($fileline, $lastline) = ($$filedesc{'line'}, $$filedesc{'data'});
  69. if ($fileline == $lineno) {
  70. return $lastline;
  71. }
  72. while (++$fileline < $lineno) {
  73. my $junk = <FILEREADER>;
  74. last if eof FILEREADER;
  75. }
  76. $lastline = <FILEREADER>;
  77. ($$filedesc{'line'}, $$filedesc{'data'}) = ($fileline, $lastline);
  78. return $lastline;
  79. }
  80. print("\n <ul>");
  81. foreach (@fpos) {
  82. my ($line, @clss) = split(/:/, $_);
  83. print("<li>", &fileref("line $line",
  84. "/$fnam", $line));
  85. if (@clss) {
  86. if ($t eq 'F' || $t eq 'f') {
  87. print(", as member of ");
  88. if ($xref{$clss[0]}) {
  89. print(&idref("class $clss[0]", $clss[0]));
  90. } else {
  91. print("class $clss[0]");
  92. }
  93. } elsif ($t eq 'C') {
  94. local $,;
  95. print(", inheriting <ul>\n");
  96. foreach (@clss) {
  97. if ($,) {
  98. print $,;
  99. } else {
  100. $,=',';
  101. }
  102. print("<li>");
  103. if ($xref{$_}) {
  104. print("class ".&idref($_, $_));
  105. } else {
  106. print("class <a title='unindexed fixme'>$_</a>");
  107. }
  108. }
  109. print(" </ul>");
  110. }
  111. }
  112. print " -- <span class='p'>" .
  113. markupstring(getline(\%filedesc, $line), $Path->{'virt'}) .
  114. "</span>\n";
  115. }
  116. close FILEREADER if $closefilereader;
  117. print(" </ul>\n");
  118. }
  119. }
  120. sub ident {
  121. my $concise = 0;
  122. print('<p class=desc>
  123. Type the full name of an identifier
  124. (a function name, variable name, typedef, etc.)
  125. <br>to summarize. Matches are <u>case-sensitive</u>.');
  126. if ($Conf->{'treename'} ne '') {
  127. print &bigexpandtemplate('<script src="$dotdoturl/script.js"></script>');
  128. }
  129. print('<form id=ident name=ident method=get action="ident" class="beforecontent">
  130. ');
  131. foreach ($Conf->allvariables) {
  132. if ($Conf->variable($_) ne $Conf->vardefault($_)) {
  133. print("<input type=hidden name=\"",$_, "\" ",
  134. "value=\"", $Conf->variable($_), "\">\n");
  135. }
  136. }
  137. print('<b><label for="i">Identifier:</label></b>
  138. <input type=text id="i" name="i"
  139. value="'.$identifier.'" size=50>
  140. <input type=submit value="Find">
  141. ');
  142. if ($Conf->{'treename'} ne '') {
  143. print '
  144. <label for="tree">using tree:</label>
  145. <select name="tree" id="tree" onchange="changetarget()">
  146. ';
  147. my @treelist = @{$Conf->{'trees'}};
  148. foreach my $othertree (@treelist) {
  149. my $default=$othertree eq $Conf->{'treename'} ? ' selected=1' : '';
  150. print "<option$default value='$othertree'>$othertree</option>
  151. ";
  152. }
  153. print (qq{</select>});
  154. }
  155. my $value = $filter;
  156. $value =~ s/&/&amp;/g;
  157. $value =~ s/"/&quot;/g;
  158. $value =~ s/</&lt;/g;
  159. $value =~ s/>/&gt;/g;
  160. print '<br>
  161. <label for="filter">Limit output to pattern:</label>
  162. <input type=text id="filter" name="filter" value="'.
  163. $value.'" size=30>';
  164. print "<br>
  165. <input type='checkbox' value='1' ";
  166. print "checked='checked' " if $strict == 1;
  167. print "id='strict' name='strict'
  168. ><label for='strict'>Don't match C++, JS, and IDL variants</label>
  169. </form>
  170. ";
  171. if ($identifier) {
  172. tie(%xref, "DB_File", $Conf->dbdir."/xref",
  173. O_RDONLY, undef, $DB_HASH) ||
  174. &fatal('No cross reference database is available for "'.$Conf->{'treename'}.'" please complain to the webmaster [cite: xref]');
  175. @refs = split(/\t/,$xref{$identifier});
  176. my $searchId = $identifier;
  177. my $searchIdFilter;
  178. unless ($strict) {
  179. my $genident = $identifier;
  180. my ($identtype, $ufirst, $lfirst);
  181. if ($genident =~ s/^([GSgs]et)([A-Z])//) {
  182. $identtype = $1;
  183. $ufirst = $2;
  184. $lfirst = lc $ufirst;
  185. $searchIdFilter = "([GSgs]et|\\b)[$ufirst$lfirst]$genident";
  186. $searchId = "$lfirst$genident";
  187. } elsif ($genident =~ s/^([a-z])//i) {
  188. $ufirst = uc $1;
  189. $lfirst = lc $ufirst;
  190. $searchIdFilter = "[$ufirst$lfirst]$genident";
  191. }
  192. my @flavors = (
  193. "get$ufirst$genident",
  194. "set$ufirst$genident",
  195. "Get$ufirst$genident",
  196. "Set$ufirst$genident",
  197. "$ufirst$genident",
  198. "$lfirst$genident",
  199. );
  200. @refs = ();
  201. foreach my $flavor (@flavors) {
  202. next if defined $identtype && $flavor =~ /^([GSgs]et)/ && $identtype !~ /$1/i;
  203. push @refs, split(/\t/,$xref{$flavor});
  204. }
  205. } else {
  206. $searchIdFilter = "\\b$identifier";
  207. }
  208. my $identifier = $identifier;
  209. $identifier =~ s/&/&amp;/g;
  210. $identifier =~ s/>/&gt;/g;
  211. $identifier =~ s/</&lt;/g;
  212. $identifier =~ s/"/&quot;/g;
  213. print("<h1>$identifier</h1>\n");
  214. my @tail = ();
  215. push @tail, "string=$searchId" if $searchId ne '';
  216. push @tail, "find=$filter" if $filter ne '';
  217. push @tail, "filter=$searchIdFilter" if $searchIdFilter ne '';
  218. my $tail = $#tail >= 0 ? '?' . join "&", @tail : '';
  219. $tail =~ s/&/&amp;/g;
  220. $tail =~ s/>/&gt;/g;
  221. $tail =~ s/</&lt;/g;
  222. $tail =~ s/"/&quot;/g;
  223. print qq{<p><i>If you can't find what you're looking for, you can always <a href="search$tail"
  224. >perform a free-text search</a> for it.</i></p>};
  225. my %f = {};
  226. if (@refs) {
  227. -f $Conf->dbdir."/fileidx" ||
  228. &fatal(
  229. 'Cross reference database is missing its file list for "'.
  230. $Conf->{'treename'}.'" please complain to the webmaster [cite: nofileidx]');
  231. -r $Conf->dbdir."/fileidx" ||
  232. &fatal(
  233. 'Cross reference database file list is not readable for "'.
  234. $Conf->{'treename'}.'" please complain to the webmaster [cite: norfileidx]');
  235. tie(%fileidx, "DB_File", $Conf->dbdir."/fileidx",
  236. O_RDONLY, undef, $DB_HASH) ||
  237. &fatal('Error opening Cross reference file list for "'.
  238. $Conf->{'treename'}.'" please complain to the webmaster [cite: fileidx]');
  239. my %normal_refh = {}, %fancy_refs = {};
  240. my %big_map = {};
  241. foreach $t (keys(%ty)) {
  242. $big_map{$t} = {};
  243. }
  244. my %local_map;
  245. foreach my $ref (@refs) {
  246. if ($ref =~ /^(.)(.*?):(.*?)(?:|:(.*?))$/) {
  247. my ($refkind, $reffnum, $refline, $classes) = ($1, $2, $3, $4);
  248. next if defined $filter && $fileidx{$reffnum} !~ /$filter/;
  249. foreach my $lineref (split(/,/, $refline)) {
  250. my $append = (defined $classes)
  251. ? "$lineref:$classes"
  252. : $lineref;
  253. if ($big_map{$refkind}{$reffnum}) {
  254. $big_map{$refkind}{$reffnum} = $big_map{$refkind}{$reffnum} . ",$append";
  255. } else {
  256. $big_map{$refkind}{$reffnum} = $append;
  257. }
  258. my $miniref = "$reffnum:$lineref";
  259. if ($refkind ne 'R' && $ty{$refkind}) {
  260. delete $normal_refh{$miniref};
  261. $fancy_refs{$miniref} = $refkind;
  262. $f{$refkind} .= "$miniref\t";
  263. } else {
  264. $normal_refh{$miniref} = $refkind unless defined $fancy_refs{$miniref};
  265. }
  266. }
  267. }
  268. }
  269. foreach $t (@tyy) {
  270. next unless ($f{$t});
  271. print("Defined as a $ty{$t} in:<ul>\n");
  272. my %kind_map = %{$big_map{$t}};
  273. foreach $fnum (sort { $a <=> $b } keys %kind_map) {
  274. my $fnam = $fileidx{$fnum};
  275. foreach my $filelist ($kind_map{$fnum}) {
  276. list_links($t, $fnam, $concise, $filelist);
  277. }
  278. }
  279. print("</ul>");
  280. }
  281. my @normal_refs = keys %normal_refh;
  282. %normal_refh = ();
  283. foreach (@normal_refs) {
  284. if (/^(.+):([\d,]+)/) {
  285. if (defined $normal_refh{$1}) {
  286. $normal_refh{$1} .= ",$2";
  287. } else {
  288. $normal_refh{$1} = $2;
  289. }
  290. }
  291. }
  292. @normal_refs = ();
  293. my $ref_count = scalar(keys %normal_refh);
  294. print('Referenced '.($ref_count > 1 ? "(in $ref_count files total) " : '')."in:\n",
  295. "<ul>\n");
  296. foreach (sort { $a <=> $b } keys %normal_refh) {
  297. list_links($t, $fileidx{$_}, $concise, $normal_refh{$_});
  298. }
  299. print("</ul>\n");
  300. untie(%fileidx);
  301. } else {
  302. print("<br><b>Not used</b>");
  303. }
  304. untie(%xref);
  305. }
  306. }
  307. ($Conf, $HTTP, $Path, $head) = &init;
  308. $identifier = $HTTP->{'param'}->{'i'};
  309. $identifier =~ s/"/\&quot;/g;
  310. $filter = $HTTP->{'param'}->{'filter'};
  311. if ($filter) {
  312. $filter =~ s/^(?:\+|\s|%20)*(.*?)(?:\+|\s|%20)*$/$1/;
  313. }
  314. if ($identifier) {
  315. $identifier =~ s/^(?:\+|\s|%20)*(.*?)(?:\+|\s|%20)*$/$1/;
  316. if (!$filter &&
  317. $identifier =~ /^(.*?)(?:\+|\s|%20)*::(?:\+|\s|%20)*(.*)$/) {
  318. ($filter, $identifier) = ($1, $2);
  319. }
  320. }
  321. my $scriptidly = $HTTP->{'param'}->{'scriptidly'};
  322. $scriptidly = $scriptidly =~ /1|yes/ ? 1 : 0 if defined $scriptidly;
  323. $strict = $HTTP->{'param'}->{'strict'};
  324. $strict = $strict =~ /1|yes/ ? 1 : 0 if defined $strict;
  325. $strict = 0 if $scriptidly;
  326. my $tree = $HTTP->{'param'}->{'tree'};
  327. if ($tree && ($tree ne $Conf->{'treename'})) {
  328. my @treelist = @{$Conf->{'trees'}};
  329. foreach my $othertree (@treelist) {
  330. next unless $othertree eq $tree;
  331. my @tail = ();
  332. push @tail, "i=" . url_quote($identifier) if $identifier ne '';
  333. push @tail, "filter=" . url_quote($filter) if $filter ne '';
  334. push @tail, "strict=1" if $strict;
  335. my $tail = $#tail >= 0 ? '?' . join "&", @tail : '';
  336. $head .= "Refresh: 0; url=../$tree/ident$tail
  337. ";
  338. }
  339. }
  340. print "$head
  341. ";
  342. &makeheader('ident');
  343. &ident;
  344. &makefooter('ident');
  345. 1;