rlm@0
|
1 #!/usr/bin/perl
|
rlm@0
|
2
|
rlm@0
|
3 use strict;
|
rlm@0
|
4 use vars qw / $javadocRoots $indexFile $resultFrame $linkFrame $gzip /;
|
rlm@0
|
5 #####################################################################
|
rlm@0
|
6 #
|
rlm@0
|
7 # javadoc-search
|
rlm@0
|
8 #
|
rlm@0
|
9 # http://sourceforge.net/projects/javadoc-search/
|
rlm@0
|
10 #
|
rlm@0
|
11 # Copyright (C) 2002-2003, Nicholas Sushkin.
|
rlm@0
|
12 #
|
rlm@0
|
13 # This program is free software; you can redistribute it and/or modify
|
rlm@0
|
14 # it under the terms of the GNU General Public License as published by
|
rlm@0
|
15 # the Free Software Foundation; either version 2 of the License, or
|
rlm@0
|
16 # (at your option) any later version.
|
rlm@0
|
17 #
|
rlm@0
|
18 # This program is distributed in the hope that it will be useful,
|
rlm@0
|
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
rlm@0
|
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
rlm@0
|
21 # GNU General Public License for more details.
|
rlm@0
|
22 #
|
rlm@0
|
23 # You should have received a copy of the GNU General Public License
|
rlm@0
|
24 # along with this program; if not, write to the Free Software
|
rlm@0
|
25 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
rlm@0
|
26 #
|
rlm@0
|
27 #
|
rlm@0
|
28 # Instructions are at http://javadoc-search.sourceforge.net/
|
rlm@0
|
29 #
|
rlm@0
|
30 #
|
rlm@0
|
31 #####################################################################
|
rlm@0
|
32 #
|
rlm@0
|
33 # $Id: javadoc-search.pl,v 1.8 2003/08/19 00:11:09 nsushkin Exp $
|
rlm@0
|
34 #
|
rlm@0
|
35 #####################################################################
|
rlm@0
|
36
|
rlm@0
|
37 ### Indexing setup
|
rlm@0
|
38
|
rlm@0
|
39 # list of subdirectories of docroot to search for javadoc index files
|
rlm@0
|
40 # Windows and Apache - prefix with drive letter and use only lowercase letters.
|
rlm@0
|
41 # $javadocRoots = [ "c:/program\ files/apache/htdocs/docs" ];
|
rlm@0
|
42 # Unix
|
rlm@0
|
43 # $javadocRoots = [ "/usr/local/apache/htdocs/docs" ];
|
rlm@0
|
44 $javadocRoots = [ "/usr/local/apache/htdocs/docs" ];
|
rlm@0
|
45
|
rlm@0
|
46 # index file, if ends with .gz will use gzip
|
rlm@0
|
47 # Windows
|
rlm@0
|
48 # $indexFile = "c:/bin/apache\ group/apache/javadoc-index.txt";
|
rlm@0
|
49 # Unix
|
rlm@0
|
50 # $indexFile = "/usr/local/apache/htdocs/docs/javadoc-index.txt.gz";
|
rlm@0
|
51 $indexFile = "/usr/local/apache/htdocs/docs/javadoc-index.txt.gz";
|
rlm@0
|
52
|
rlm@0
|
53 ### Display style setup
|
rlm@0
|
54
|
rlm@0
|
55 # if $resultFrame is not empty, display search results in this frame
|
rlm@0
|
56 $resultFrame = "";
|
rlm@0
|
57
|
rlm@0
|
58 # if $linkFrame is not empty, open javadoc links in this frame
|
rlm@0
|
59 $linkFrame = "";
|
rlm@0
|
60
|
rlm@0
|
61 ### Auxillary programs setup
|
rlm@0
|
62
|
rlm@0
|
63 # which gzip
|
rlm@0
|
64 $gzip = "/usr/bin/gzip";
|
rlm@0
|
65
|
rlm@0
|
66 # nothing below is customizable
|
rlm@0
|
67 #####################################################################
|
rlm@0
|
68 use Getopt::Std;
|
rlm@0
|
69 use File::Find;
|
rlm@0
|
70
|
rlm@0
|
71 my @indexFiles;
|
rlm@0
|
72 my %links;
|
rlm@0
|
73
|
rlm@0
|
74 (my $rev = '$Revision: 1.8 $') =~ s/^\$\w+: ([\.\d]+) \$$/$1/;
|
rlm@0
|
75
|
rlm@0
|
76 sub usage
|
rlm@0
|
77 {
|
rlm@0
|
78 print STDERR <<EOUSAGE;
|
rlm@0
|
79 Javadoc Search $rev
|
rlm@0
|
80
|
rlm@0
|
81 Usage: $0 [-h] [-r]
|
rlm@0
|
82
|
rlm@0
|
83 -h prints this help
|
rlm@0
|
84 -r builds index
|
rlm@0
|
85
|
rlm@0
|
86 This is a cgi script to search javadoc for classes, members, and methods
|
rlm@0
|
87 using an index.
|
rlm@0
|
88 EOUSAGE
|
rlm@0
|
89
|
rlm@0
|
90 }
|
rlm@0
|
91
|
rlm@0
|
92 #
|
rlm@0
|
93 # Build index part
|
rlm@0
|
94 #
|
rlm@0
|
95 sub indexWrite
|
rlm@0
|
96 {
|
rlm@0
|
97 print STDERR "Writing all ", indexGetLinkCount(), " links to $indexFile .. ";
|
rlm@0
|
98
|
rlm@0
|
99 if ($indexFile =~ /\.gz$/)
|
rlm@0
|
100 {
|
rlm@0
|
101 open(OUTPUT, "| $gzip -c > \"$indexFile\"") || die "unable to gzip to $indexFile: $!\n";
|
rlm@0
|
102 }
|
rlm@0
|
103 else
|
rlm@0
|
104 {
|
rlm@0
|
105 open(OUTPUT, ">" . $indexFile) || die "unable to write to $indexFile: $!\n";
|
rlm@0
|
106 }
|
rlm@0
|
107
|
rlm@0
|
108 my $oldSearchKey = "";
|
rlm@0
|
109 foreach (sort { $links{$a} cmp $links{$b} } keys %links)
|
rlm@0
|
110 {
|
rlm@0
|
111 my $searchKey = $links{$_};
|
rlm@0
|
112 if ($searchKey ne $oldSearchKey)
|
rlm@0
|
113 {
|
rlm@0
|
114 if ($oldSearchKey ne "") { print OUTPUT "\n"; }
|
rlm@0
|
115 print OUTPUT $searchKey;
|
rlm@0
|
116 }
|
rlm@0
|
117 print OUTPUT "\t", $_;
|
rlm@0
|
118
|
rlm@0
|
119 $oldSearchKey = $searchKey;
|
rlm@0
|
120 }
|
rlm@0
|
121 print OUTPUT "\n";
|
rlm@0
|
122
|
rlm@0
|
123 close(OUTPUT);
|
rlm@0
|
124
|
rlm@0
|
125 print STDERR "done\n";
|
rlm@0
|
126 }
|
rlm@0
|
127
|
rlm@0
|
128 sub indexGetLinkCount
|
rlm@0
|
129 {
|
rlm@0
|
130 scalar(keys %links);
|
rlm@0
|
131 }
|
rlm@0
|
132
|
rlm@0
|
133 sub indexRebuild
|
rlm@0
|
134 {
|
rlm@0
|
135 find(\&indexFileFinder, @$javadocRoots);
|
rlm@0
|
136
|
rlm@0
|
137 foreach (@indexFiles)
|
rlm@0
|
138 {
|
rlm@0
|
139 parseLinks($$_[0], $$_[1]);
|
rlm@0
|
140 }
|
rlm@0
|
141 }
|
rlm@0
|
142
|
rlm@0
|
143 sub indexFileFinder
|
rlm@0
|
144 {
|
rlm@0
|
145 return unless -f $File::Find::name;
|
rlm@0
|
146 return unless /^index-.*html??/;
|
rlm@0
|
147
|
rlm@0
|
148 push @indexFiles, [$File::Find::name, $File::Find::dir];
|
rlm@0
|
149 }
|
rlm@0
|
150
|
rlm@0
|
151 sub indexAddLink
|
rlm@0
|
152 {
|
rlm@0
|
153 my $key = shift;
|
rlm@0
|
154 my $link = shift;
|
rlm@0
|
155
|
rlm@0
|
156 $links{$link} = $key;
|
rlm@0
|
157 }
|
rlm@0
|
158
|
rlm@0
|
159 sub parseLinks()
|
rlm@0
|
160 {
|
rlm@0
|
161 my $fileName = shift;
|
rlm@0
|
162 my $dirName = shift;
|
rlm@0
|
163
|
rlm@0
|
164 print STDERR "Parsing ", $fileName, ": ";
|
rlm@0
|
165
|
rlm@0
|
166 open(FILE, $fileName);
|
rlm@0
|
167
|
rlm@0
|
168 while(<FILE>)
|
rlm@0
|
169 {
|
rlm@0
|
170 if($_ =~ m/<A[^>]+?HREF\s*=\s*[\"\']?([^\'\" >]+?)[ \'\"]?(>| title=)/sig)
|
rlm@0
|
171 {
|
rlm@0
|
172 parseLink($1, $dirName);
|
rlm@0
|
173 }
|
rlm@0
|
174 }
|
rlm@0
|
175
|
rlm@0
|
176 close(FILE);
|
rlm@0
|
177
|
rlm@0
|
178 print STDERR indexGetLinkCount(), " links\n";
|
rlm@0
|
179 }
|
rlm@0
|
180
|
rlm@0
|
181 sub parseLink()
|
rlm@0
|
182 {
|
rlm@0
|
183 my $link = shift;
|
rlm@0
|
184 my $dirName = shift;
|
rlm@0
|
185
|
rlm@0
|
186 return if $link =~ qr'^(http|ftp)://'i;
|
rlm@0
|
187
|
rlm@0
|
188 # print "# link=", $link, "\n";
|
rlm@0
|
189
|
rlm@0
|
190 my $abslink = ( $link =~ qr'^[\./]*([^\./].*)' ) ? $1 : $link;
|
rlm@0
|
191 # print "# abslink= $abslink\n";
|
rlm@0
|
192
|
rlm@0
|
193 return unless $abslink =~ qr'/';
|
rlm@0
|
194
|
rlm@0
|
195 my ($file,$anchor) = split '#', $abslink;
|
rlm@0
|
196 # print "# file=$file, anchor=$anchor\n";
|
rlm@0
|
197
|
rlm@0
|
198 my $class = ($file =~ /(.*)\.html??/ ) ? $1 : return;
|
rlm@0
|
199 $class =~ tr{\/}{\.};
|
rlm@0
|
200
|
rlm@0
|
201 # print "# class=", $class, "\n";
|
rlm@0
|
202 # print "# dirname=", $dirName, "\n";
|
rlm@0
|
203
|
rlm@0
|
204 # cancel out ".."
|
rlm@0
|
205 if ($link =~ /^\.\.\//)
|
rlm@0
|
206 {
|
rlm@0
|
207 my @linkSegs = split '/', $link;
|
rlm@0
|
208 my @dirSegs = split '/', $dirName;
|
rlm@0
|
209
|
rlm@0
|
210 while (@linkSegs[0] eq '..' and $#dirSegs >= 0)
|
rlm@0
|
211 {
|
rlm@0
|
212 shift @linkSegs;
|
rlm@0
|
213 pop @dirSegs;
|
rlm@0
|
214 }
|
rlm@0
|
215 $link = join '/', @linkSegs;
|
rlm@0
|
216 $dirName = join '/', @dirSegs;
|
rlm@0
|
217 }
|
rlm@0
|
218 my $fullLink = ( $link =~ /^\// ) ? $link : $dirName . "/" . $link;
|
rlm@0
|
219
|
rlm@0
|
220 my $key = $anchor eq "" ? $class : $class . '#' . $anchor;
|
rlm@0
|
221 indexAddLink($key, $fullLink);
|
rlm@0
|
222 }
|
rlm@0
|
223
|
rlm@0
|
224 #
|
rlm@0
|
225 # CGI part
|
rlm@0
|
226 #
|
rlm@0
|
227 use CGI qw(:standard);
|
rlm@0
|
228
|
rlm@0
|
229 my $searchTypes = {'c'=>'class','cm'=>'class#member','cma'=>'class#member(args)'};
|
rlm@0
|
230
|
rlm@0
|
231 sub topFrameGenerate
|
rlm@0
|
232 {
|
rlm@0
|
233 Delete('render');
|
rlm@0
|
234 param('render', 'query');
|
rlm@0
|
235 my $queryFrameUrl = self_url;
|
rlm@0
|
236
|
rlm@0
|
237 Delete('render');
|
rlm@0
|
238 param('render', 'noResults');
|
rlm@0
|
239 my $noResultsFrameUrl = self_url;
|
rlm@0
|
240
|
rlm@0
|
241 return
|
rlm@0
|
242 header(),
|
rlm@0
|
243 html(head(title('Javadoc search')),
|
rlm@0
|
244 frameset({-rows => '150,*'},
|
rlm@0
|
245 frame({-name => 'query', -src => $queryFrameUrl}),
|
rlm@0
|
246 frame({-name => $resultFrame, -src => $noResultsFrameUrl})));
|
rlm@0
|
247 }
|
rlm@0
|
248
|
rlm@0
|
249 sub noResultsGenerate
|
rlm@0
|
250 {
|
rlm@0
|
251 return
|
rlm@0
|
252 header,
|
rlm@0
|
253 start_html('Javadoc search'),
|
rlm@0
|
254 h2('No results yet'),
|
rlm@0
|
255 end_html,
|
rlm@0
|
256 "\n";
|
rlm@0
|
257 }
|
rlm@0
|
258
|
rlm@0
|
259 sub searchFormGenerate
|
rlm@0
|
260 {
|
rlm@0
|
261 Delete('render');
|
rlm@0
|
262
|
rlm@0
|
263 return
|
rlm@0
|
264 h1('Javadoc search'),
|
rlm@0
|
265 $resultFrame ? start_form(-target => $resultFrame, -action=>script_name) : start_form(-action=>script_name),
|
rlm@0
|
266 "Search pattern ",
|
rlm@0
|
267 textfield(-name=>'pattern', -size=>15),
|
rlm@0
|
268 " in ",
|
rlm@0
|
269 scrolling_list(-name=>'type',
|
rlm@0
|
270 -values=>[sort(keys(%$searchTypes))],
|
rlm@0
|
271 -labels=>$searchTypes,
|
rlm@0
|
272 -defaults=>['c'],
|
rlm@0
|
273 -size=>1),
|
rlm@0
|
274 " and display ",
|
rlm@0
|
275 scrolling_list(-name=>'results',
|
rlm@0
|
276 -values=>['1', '10', '20', '50', '0'],
|
rlm@0
|
277 -labels=>{'1'=>'1', '10'=>'10', '20'=>'20', '50'=>'50', '0'=>'All'},
|
rlm@0
|
278 -defaults=>['10'],
|
rlm@0
|
279 -size=>1),
|
rlm@0
|
280 " results ",
|
rlm@0
|
281 submit(-name=>'go', -value=>'Go'), submit(-name=>'lucky', -value=>'Go!'),
|
rlm@0
|
282 $resultFrame ? hidden(-name => 'render', -default => 'results') : "",
|
rlm@0
|
283 end_form,
|
rlm@0
|
284 $resultFrame ? "" : hr;
|
rlm@0
|
285 }
|
rlm@0
|
286
|
rlm@0
|
287 sub doSearch
|
rlm@0
|
288 {
|
rlm@0
|
289 my ($pattern, $type, $results) = @_;
|
rlm@0
|
290
|
rlm@0
|
291 if (! -r $indexFile)
|
rlm@0
|
292 {
|
rlm@0
|
293 print strong("Error: index file is not readable");
|
rlm@0
|
294 return;
|
rlm@0
|
295 }
|
rlm@0
|
296
|
rlm@0
|
297 if ($indexFile =~ /\.gz$/)
|
rlm@0
|
298 {
|
rlm@0
|
299 open(INPUT, "$gzip -dc \"$indexFile\" |") || die "unable to un-gzip $indexFile: $!\n";
|
rlm@0
|
300 }
|
rlm@0
|
301 else
|
rlm@0
|
302 {
|
rlm@0
|
303 open(INPUT, $indexFile) || die "unable to read $indexFile: $!\n";
|
rlm@0
|
304 }
|
rlm@0
|
305
|
rlm@0
|
306 my $docRoot = $ENV{'DOCUMENT_ROOT'};
|
rlm@0
|
307 my @matches;
|
rlm@0
|
308
|
rlm@0
|
309 INPUTLINE:
|
rlm@0
|
310 while(<INPUT>)
|
rlm@0
|
311 {
|
rlm@0
|
312 chomp;
|
rlm@0
|
313 my ($key, @urls) = split (/\t/);
|
rlm@0
|
314
|
rlm@0
|
315 for ($key)
|
rlm@0
|
316 {
|
rlm@0
|
317 if (($type eq "c" and /\#/) ||
|
rlm@0
|
318 ($type eq "cm" and !(/\#/ and !/\)/)) ||
|
rlm@0
|
319 ($type eq "cma" and !(/\#/ and /\)/)))
|
rlm@0
|
320 {
|
rlm@0
|
321 next INPUTLINE;
|
rlm@0
|
322 }
|
rlm@0
|
323 }
|
rlm@0
|
324
|
rlm@0
|
325 if ($key =~ /$pattern/ and ($results == 0 or $#matches < $results) )
|
rlm@0
|
326 {
|
rlm@0
|
327 push @matches, [ ( $key, map { s/$docRoot//; $_ } @urls ) ];
|
rlm@0
|
328 }
|
rlm@0
|
329
|
rlm@0
|
330 last if $results > 0 and $#matches >= $results;
|
rlm@0
|
331
|
rlm@0
|
332 }
|
rlm@0
|
333 close(INPUT);
|
rlm@0
|
334
|
rlm@0
|
335 return \@matches;
|
rlm@0
|
336 }
|
rlm@0
|
337
|
rlm@0
|
338 sub displayLuckyMatch
|
rlm@0
|
339 {
|
rlm@0
|
340 my $matches = shift;
|
rlm@0
|
341
|
rlm@0
|
342 if ( $#$matches < 0 )
|
rlm@0
|
343 {
|
rlm@0
|
344 print
|
rlm@0
|
345 header,
|
rlm@0
|
346 start_html('No matches'),
|
rlm@0
|
347 p("No matches"),
|
rlm@0
|
348 end_html;
|
rlm@0
|
349 }
|
rlm@0
|
350 else
|
rlm@0
|
351 {
|
rlm@0
|
352 print
|
rlm@0
|
353 $linkFrame ? header(-target => $linkFrame) : "",
|
rlm@0
|
354 redirect('-location'=> $$matches[0][1]);
|
rlm@0
|
355 }
|
rlm@0
|
356 }
|
rlm@0
|
357
|
rlm@0
|
358
|
rlm@0
|
359 sub displayMatches
|
rlm@0
|
360 {
|
rlm@0
|
361 my $matches = shift;
|
rlm@0
|
362
|
rlm@0
|
363 if ( $#$matches < 0 )
|
rlm@0
|
364 {
|
rlm@0
|
365 print p("No matches");
|
rlm@0
|
366 }
|
rlm@0
|
367 else
|
rlm@0
|
368 {
|
rlm@0
|
369 print
|
rlm@0
|
370 p(
|
rlm@0
|
371 "Searching pattern ", em(escapeHTML(param('pattern'))),
|
rlm@0
|
372 " in ", em(escapeHTML($$searchTypes{param('type')}))),
|
rlm@0
|
373 h2("Search results"),
|
rlm@0
|
374 "<ul>";
|
rlm@0
|
375
|
rlm@0
|
376 foreach my $match (@$matches)
|
rlm@0
|
377 {
|
rlm@0
|
378 my $searchKey = escapeHTML(shift @$match);
|
rlm@0
|
379 my $cnt = -1;
|
rlm@0
|
380 print li( map {
|
rlm@0
|
381 a( $linkFrame ? {-href => $_, -target => $linkFrame } : { -href => $_}, ( $cnt++ >= 0 ? "alt".($cnt) : $searchKey) )
|
rlm@0
|
382 } @$match );
|
rlm@0
|
383
|
rlm@0
|
384 }
|
rlm@0
|
385
|
rlm@0
|
386 print "</ul>";
|
rlm@0
|
387 }
|
rlm@0
|
388 }
|
rlm@0
|
389
|
rlm@0
|
390 #
|
rlm@0
|
391 # main
|
rlm@0
|
392 #
|
rlm@0
|
393 use vars qw / $opt_h $opt_r /;
|
rlm@0
|
394
|
rlm@0
|
395 if (server_software() eq 'cmdline')
|
rlm@0
|
396 {
|
rlm@0
|
397 getopts("rh");
|
rlm@0
|
398
|
rlm@0
|
399 if ($opt_h)
|
rlm@0
|
400 {
|
rlm@0
|
401 usage;
|
rlm@0
|
402 exit;
|
rlm@0
|
403 }
|
rlm@0
|
404
|
rlm@0
|
405 if ($opt_r)
|
rlm@0
|
406 {
|
rlm@0
|
407 indexRebuild;
|
rlm@0
|
408 indexWrite;
|
rlm@0
|
409 exit;
|
rlm@0
|
410 }
|
rlm@0
|
411 }
|
rlm@0
|
412
|
rlm@0
|
413
|
rlm@0
|
414 if (param('render'))
|
rlm@0
|
415 {
|
rlm@0
|
416 $resultFrame = 'results';
|
rlm@0
|
417 $linkFrame = '';
|
rlm@0
|
418 }
|
rlm@0
|
419
|
rlm@0
|
420 my $thisFrame = param('render');
|
rlm@0
|
421
|
rlm@0
|
422 if ($thisFrame eq 'topFrame')
|
rlm@0
|
423 {
|
rlm@0
|
424 print topFrameGenerate();
|
rlm@0
|
425 exit 0;
|
rlm@0
|
426 }
|
rlm@0
|
427 elsif ($thisFrame eq 'noResults')
|
rlm@0
|
428 {
|
rlm@0
|
429 print noResultsGenerate();
|
rlm@0
|
430 exit 0;
|
rlm@0
|
431 }
|
rlm@0
|
432
|
rlm@0
|
433 unless (param('lucky') and param('pattern'))
|
rlm@0
|
434 {
|
rlm@0
|
435 print
|
rlm@0
|
436 header,
|
rlm@0
|
437 start_html('Javadoc search'),
|
rlm@0
|
438 defined(param('pattern')) && $resultFrame ? "" : searchFormGenerate();
|
rlm@0
|
439 }
|
rlm@0
|
440
|
rlm@0
|
441 if (param('pattern'))
|
rlm@0
|
442 {
|
rlm@0
|
443 my $matches = doSearch(param('pattern'), param('type'), param('results'));
|
rlm@0
|
444
|
rlm@0
|
445 if (param('lucky'))
|
rlm@0
|
446 {
|
rlm@0
|
447 displayLuckyMatch($matches);
|
rlm@0
|
448 }
|
rlm@0
|
449 else
|
rlm@0
|
450 {
|
rlm@0
|
451 displayMatches($matches);
|
rlm@0
|
452 }
|
rlm@0
|
453 }
|
rlm@0
|
454 else
|
rlm@0
|
455 {
|
rlm@0
|
456 if ($thisFrame ne 'query')
|
rlm@0
|
457 {
|
rlm@0
|
458 print p('Specify non-blank search pattern');
|
rlm@0
|
459 }
|
rlm@0
|
460 }
|
rlm@0
|
461
|
rlm@0
|
462 unless (param('lucky') and param('pattern'))
|
rlm@0
|
463 {
|
rlm@0
|
464 print end_html;
|
rlm@0
|
465 }
|