search 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. #!/usr/bin/perl
  2. # $Id: search,v 1.10 2006/12/07 04:59:38 reed%reedloden.com Exp $
  3. # search -- Freetext search
  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. $maxhits = 1000;
  28. my ($openlist, $lastfilepath, $skip);
  29. my $styles="
  30. <style type='text/css'>";
  31. my $stylee="</style>
  32. ";
  33. sub toggle_style
  34. {
  35. my ($n, $m) = @_;
  36. my $s=0; my $t=10;
  37. my @inline = (), @none = ();
  38. push @none, ".$m$s"."_".(($n-1 % $t) % 10);
  39. push @inline, ".$m$s"."_".(($n % $t) % 10);
  40. if (($n % $t) == 0) {
  41. do {
  42. $n = ($n / 10) | 0;
  43. ++$s;
  44. if ($n % 10 == 0) {
  45. push @none, ".$m$s"."_9";
  46. push @inline, ".$m$s"."_0";
  47. }
  48. } while ($n>=10 && (($n % 10) == 0));
  49. push @none, ".$m$s"."_".(($n -1) % 10);
  50. push @inline, ".$m$s"."_".($n % 10);
  51. }
  52. return join(',',@none)."{display:none;}
  53. ".join(',',@inline)."{display:inline;}";
  54. }
  55. sub display_line
  56. {
  57. my ($glimpseline, $re) = @_;
  58. $sourceroot = $Conf->sourceroot;
  59. $glimpseline =~ s/$sourceroot//;
  60. ($file, $line, $text) =
  61. $glimpseline =~ /(.*?):\s*(\d+)\s*:(.*)/;
  62. if (length($text) > 160) {
  63. # the string is way too long
  64. # "hello cruel world what time is it this day. We are here to \
  65. # celebrate the beginning of things which no one cares about \
  66. # because it is so very important. When for other reasons it \
  67. # becomes clear that no one really cares. We should stop it."
  68. my $context = '.{0,20}';
  69. $text =~ s/.*?($context$re$context)/..$1../g;
  70. $text =~ s/($re$context)((?!$re).)*$/$1.../;
  71. $text = '.' . $text;
  72. }
  73. my $path='';
  74. my $filename;
  75. my $skip = $lastfilepath eq $file;
  76. #$skip = 0;
  77. $lastfilepath = $file;
  78. if ($openlist && !$skip) {
  79. $openlist = 0;
  80. print ('</ul>');
  81. }
  82. ($file,$filename)=split m|/(?!.*/)|, $file;
  83. foreach my $filepart ($file =~ m{^/?$} ? ('') : split m|/|, $file) {
  84. $path .= "$filepart/";
  85. unless ($skip) {
  86. print(&fileref($filepart ? $filepart : '/', "$path"),
  87. $filepart && '/');
  88. }
  89. }
  90. my $filepath = $path ? $path . $filename : "/$filename";
  91. my @frargs = ();
  92. if ($filename =~ /\.html?$/) {
  93. @frargs = ("force=1");
  94. }
  95. unless ($skip) {
  96. print(&fileref("$filename", "$filepath"));
  97. print(&blamerefs($file.'/'.$filename));
  98. }
  99. unless ($skip) {
  100. print ('<ul>');
  101. $openlist = 1;
  102. }
  103. print ('<li>');
  104. print(&fileref("line $line", "$filepath", $line, @frargs),
  105. " -- ".markupstring($text, "$path")."<br>\n");
  106. }
  107. sub escape_re {
  108. $re = shift;
  109. $re =~ s/([-.*+?{}|()^\\\[\]`])/\\$1/g;
  110. return $re;
  111. }
  112. sub escape_comment {
  113. my $comment = shift;
  114. $comment =~ s/\&/\&amp;/g;
  115. $comment =~ s/</\&lt;/g;
  116. $comment =~ s/>/\&gt;/g;
  117. $comment =~ s/"/\&quot;/g;
  118. $comment =~ s/-/\&#45;/g;
  119. return $comment;
  120. }
  121. sub print_ident_hints
  122. {
  123. my ($requestedsearch) = @_;
  124. my @idents = ();
  125. my @terms = split /[^~a-z_0-9]+/i, $requestedsearch;
  126. if (scalar @terms) {
  127. my %list = ();
  128. foreach my $term (@terms) {
  129. $list{$term} = 1;
  130. }
  131. @terms = keys %list;
  132. use DB_File;
  133. my %xref;
  134. if (tie(%xref, "DB_File", $Conf->dbdir."/xref",
  135. O_RDONLY, undef, $DB_HASH)) {
  136. foreach my $term (@terms) {
  137. if (defined $xref{$term}) {
  138. push @idents, '<a href="ident?i='.$term.'">'.$term.'</a>';
  139. }
  140. }
  141. if (scalar @idents) {
  142. print '<p>For faster searches, you could search for these identifiers: '.
  143. join(', ', @idents) . '</p>';
  144. }
  145. untie(%xref);
  146. }
  147. }
  148. }
  149. sub search {
  150. print(qq{<p class=desc>
  151. Free-text search through the source code, including comments.
  152. <br>By default, this form treats all characters as literals.
  153. <br>Search strings can have a maximum of 29 characters.
  154. <br>Read the <a href="search-help.html">documentation</A>
  155. for help with glimpse's regular expression syntax,
  156. });
  157. my $changetarget = '';
  158. print &bigexpandtemplate('<script src="$dotdoturl/script.js"></script>');
  159. my $note;
  160. my @filters = ();
  161. my $displayedsearch = escape_comment($searchtext);
  162. my $requestedsearch = $searchtext;
  163. if ($searchtext =~ /\S/) {
  164. if ($searchtext !~ /[a-zA-Z0-9]/) {
  165. push @filters, ($regexp ? $searchtext : escape_re($searchtext));
  166. $searchtext = $search_sensitive ? '[a-zA-Z]' : '[a-z]';
  167. $regexp = 1;
  168. $note = "<p><strong>Your search did not contain any indexed characters,
  169. and was converted into a filter.</strong></p>\n";
  170. } elsif (!$regexp && $searchtext =~ /\s*(.{29}).+?\s*/) {
  171. push @filters, escape_re($searchtext);
  172. $searchtext = $1;
  173. $note = "<p><strong>Your search was too long, the full search was
  174. converted into a filter.</strong></p>\n";
  175. }
  176. }
  177. print('<form name=search id=search method=get action="search" class="beforecontent">');
  178. my @extras = qw(rev line mark);
  179. foreach $extra (@extras) {
  180. if (defined $HTTP->{'param'}->{$extra} &&
  181. $HTTP->{'param'}->{$extra} =~ /^([-0-9a-f,]+)$/i) {
  182. print("<input type='hidden' value='$1'>
  183. ");
  184. $args .= "&$extra=$1";
  185. }
  186. }
  187. print('<table><tr><td>');
  188. foreach ($Conf->allvariables) {
  189. if ($Conf->variable($_) ne $Conf->vardefault($_)) {
  190. print('<input type=hidden name="',$_, '" ',
  191. 'value="', $Conf->variable($_), '">
  192. ');
  193. }
  194. }
  195. print('<b>
  196. <label for="string">Search for:</label></b></td>
  197. <td>
  198. <input type=text id="string" name="string"
  199. value="',$displayedsearch,'" size=30>
  200. <input type=submit value="search"><br>
  201. </td></tr><tr><td></td><td>
  202. <input type="checkbox" id="regexp" name="regexp"');
  203. if ($regexp) {
  204. print (' checked');
  205. print (' value="1"');
  206. }
  207. print '><label for="regexp">Regular Expression Search</label>
  208. </td><tr><td><td><input type="checkbox" id="case" name="case"';
  209. if ($search_sensitive) {
  210. print (' checked');
  211. print (' value="1"');
  212. }
  213. print '><label for="case">Case sensitive</label>
  214. ';
  215. my $value = escape_comment($find);
  216. print('</td>
  217. <tr><td><label for="find">in files matching:</label></td>
  218. <td><input type=text id="find" name="find" value="'.
  219. $value.
  220. '" size=30>');
  221. if ($find_warning) {
  222. print ' a suggestion was made by your browser, but it was ignored in favor of the provided string, if you empty the string and search again, it will be honored.';
  223. }
  224. print ' <label for="findi">Suggestions from our users:</label>
  225. <select id="findi" name="findi" onchange="changefindpreset()">
  226. <option value="">none of these</option>';
  227. # this needs to move into Local.pm
  228. @find_options = qw(
  229. \.xul$
  230. \.dtd$
  231. \.po$
  232. \.c
  233. \.h$
  234. \..$
  235. \.[chj]
  236. \.x.l
  237. \.idl$
  238. \.css
  239. \.htm
  240. \.xml
  241. \.js
  242. \.rdf
  243. \.in
  244. debian/control
  245. );
  246. $findi = cleanFind($findi);
  247. foreach my $find_opt (@find_options) {
  248. my $find_default = ($find_opt eq $findi)
  249. ? ' selected="selected"' : '';
  250. print "<option$find_default value='$find_opt'>$find_opt</option>
  251. ";
  252. }
  253. print '</select>
  254. ';
  255. $value = escape_comment($filter);
  256. print '</td></tr>
  257. <tr><td><label for="filter">Limit output to pattern:</label></td>
  258. <td><input type=text id="filter" name="filter" value="'.
  259. $value.'" size=30></td></tr>
  260. <tr><td><label for="hitlimit">Limit matches per file to:</label></td>
  261. <td><input type=text id="hitlimit" name="hitlimit" value="'.
  262. $hitlimit.'" size=10>';
  263. if ($Conf->{'treename'} ne '') {
  264. print('</td></tr><tr><td>
  265. <label for="tree">using tree:</label></td><td>
  266. <select name="tree" id="tree" onchange="changetarget()">
  267. ');
  268. my @treelist = @{$Conf->{'trees'}};
  269. foreach my $othertree (@treelist) {
  270. my $default = $othertree eq $Conf->{'treename'}
  271. ? ' selected=1' : '';
  272. print "<option$default value='$othertree'>$othertree</option>
  273. ";
  274. }
  275. print '</select>';
  276. }
  277. print '</td></tr></table>
  278. </form>
  279. ';
  280. $| = 1; print('');
  281. if ($isregexp && $searchtext ne "" && $searchtext =~ /[\[\]{}\\]/) {
  282. my $bracketsearchtext = $searchtext;
  283. my $doublebackslash = '\\\\';
  284. $bracketsearchtext =~ s/$doublebackslash$doublebackslash//g;
  285. $bracketsearchtext =~ s/[^\[\]{}\\]/x/g;
  286. $bracketsearchtext =~ s/\\[\[\]]/x/g;
  287. my @brackets = ();
  288. my $start_or_not_escape = '(?:^|[^\\\\])';
  289. if (($bracketsearchtext =~ s/$start_or_not_escape\[//g) !=
  290. ($bracketsearchtext =~ s/$start_or_not_escape\]//g)) {
  291. push @brackets, qw( [ ] );
  292. }
  293. if (($bracketsearchtext =~ s/$start_or_not_escape\{//g) !=
  294. ($bracketsearchtext =~ s/$start_or_not_escape\}//g)) {
  295. push @brackets, qw( { } );
  296. }
  297. if (scalar @brackets) {
  298. $searchtext = '';
  299. print "<em>Can't search with mismatched brackets: ".join(', ', @brackets)."</em><br>
  300. ";
  301. }
  302. }
  303. if (! -e $Conf->glimpsebin) {
  304. &fatal("Search isn't available;
  305. please complain to the webmaster [cite: bad_glimpsebin]");
  306. } elsif (($Conf->{'treename'} eq '/search')) {
  307. # Bug 465245 MXR search gives error for non tree in tree configuration
  308. } elsif (! -d $Conf->dbdir) {
  309. &fatal("Search isn't available;
  310. please complain to the webmaster [cite: bad_dbdir]");
  311. } elsif (! -r $Conf->dbdir . '/.glimpse_index') {
  312. &fatal("Search isn't available;
  313. please complain to the webmaster [cite: bad_glimpseindex]");
  314. } elsif ($searchtext ne "") {
  315. print '<hr>
  316. ';
  317. if ($find) {
  318. my $displayedfind = escape_comment($find);
  319. print '<p><i>Searching <a href="find?string=' . $displayedfind . '">these files</a>
  320. for <a href="search?string=' . $displayedsearch . '">this text</a>.</i></p>';
  321. }
  322. print_ident_hints($requestedsearch);
  323. print $note;
  324. push @filters, $filter if $filter;
  325. if ($regexp) {
  326. $searchtext =~ s/([~;,><])/\\$1/g;
  327. } else {
  328. push @filters, escape_re($searchtext) if $search_sensitive;
  329. $searchtext =~ s/([~;,#><\-\$.^*^|()\!\[\]])/\\$1/g;
  330. }
  331. @execparams = ($Conf->glimpsebin,"-i","-H",$Conf->dbdir,'-y','-n');
  332. if ($find) {
  333. $find =~ s/-/\\-/g;
  334. push @execparams, ('-F', $find);
  335. }
  336. push @execparams, ('-e', $searchtext);
  337. my $glimpsepid;
  338. unless ($glimpsepid = open(GLIMPSE, "-|")) {
  339. open(STDERR, ">&STDOUT");
  340. $!='';
  341. exec(@execparams);
  342. print "Glimpse subprocess died unexpectedly: $!
  343. ";
  344. exit;
  345. }
  346. if (0) {
  347. local $, = "\n";
  348. print "<!--
  349. @execparams;
  350. -->";
  351. }
  352. $numlines = 0;
  353. my $search_case = undef;
  354. if ($search_sensitive) {
  355. $search_case = $searchtext;
  356. }
  357. print("<h1>$displayedsearch</h1>\n");
  358. my $hit_file_count = 0;
  359. my $hit_for_current_file = 0;
  360. my $prev_file;
  361. print "$styles
  362. .status.searching {display:block}
  363. .status {display: none}
  364. $stylee
  365. <p><b>
  366. <span class='status searching'>Searching... </span>
  367. <span class='status error_toolong'>Pattern too long. Use a maximum 29 characters.</span>
  368. <span class='status matches_zero'>No matching files</span>
  369. <span class='status matches_one'>Found one matching line</span>
  370. <span class='status matches_n'>Found
  371. $styles
  372. .m0, .m1, .m2, .f0, .f1, .f2, .matches_f {display:none}
  373. .m0_2 {display:inline}
  374. $stylee";
  375. for (my $q1=3;$q1--;) {
  376. for (my $r1=0;$r1<10;++$r1) {
  377. print "<span class='m$q1 m$q1"."_$r1'>$r1</span>";
  378. }
  379. }
  380. print " matching lines
  381. <span class='status matches_f'> in ";
  382. for (my $q=3;$q--;) {
  383. for (my $r=0;$r<10;++$r) {
  384. print "<span class='f$q f$q"."_$r'>$r</span>";
  385. }
  386. }
  387. print " files</span></span>
  388. <span class='status matches_max'>Too many hits, displaying the first $maxhits</span>
  389. </b></p>
  390. ";
  391. my $glimpse_error_reported = 0;
  392. my $glimpse_search_may_fail = 0;
  393. LINE: while (my $line = <GLIMPSE>) {
  394. if (!$numlines) {
  395. if ($line =~ /^Warning: No files were indexed! Exiting\.\.\./) {
  396. print "No files in search index, please complain to the webmaster [cite: emptyglimpsetarget]<br>\n";
  397. $glimpse_error_reported = 1;
  398. last;
  399. }
  400. if ($line =~ /^in get_table: (table overflow|)/) {
  401. print "Glimpse database is broken";
  402. $glimpse_error_reported = 1;
  403. last;
  404. }
  405. if ($line =~ /^Warning: pattern has words present in the stop-list: must SEARCH the files$/) {
  406. next;
  407. }
  408. if ($line =~ /^Warning! Error in the format of the index!$/) {
  409. next;
  410. }
  411. if ($line =~ /^[^:]*glimpse: unmatched '\[', '\]' \(use \\\[, \\\] to search for \[, \]\)/) {
  412. $glimpse_search_may_fail = 1;
  413. next;
  414. }
  415. if ($glimpse_search_may_fail && ($line =~ /^[^:]*glimpse: error in searching index$/)) {
  416. $glimpse_search_may_fail = 0;
  417. next;
  418. }
  419. if ($line =~ /^[^:]*:[^:]*(parse error at|unmatched)|^glimpse: error in searching index$/) {
  420. print "Pattern can't be handled today, please file a
  421. <a href='https://bugzilla.mozilla.org/enter_bug.cgi?product=Webtools&component=MXR&short_desc=glimpse+parse+error&bug_file_loc=please-fill-this-in'
  422. >bug</a>.<br>";
  423. $line = escape_comment($line);
  424. print "<!--
  425. $line
  426. -->";
  427. $glimpse_error_reported = 1;
  428. next;
  429. }
  430. if ($line =~ /^[^:]*:[^:]*pattern has some meta-characters interpreted by agrep!/) {
  431. print ("Pattern has some meta-characters.
  432. <em>Try moving characters that are not letters (a-z) or numbers (0-9)
  433. to the filter field</em><br>\n");
  434. $glimpse_error_reported = 1;
  435. next;
  436. }
  437. if ($line =~ /^[^:]*:[^:]*pattern too long/) {
  438. print ("Pattern too long. Use a maximum of 29 characters.
  439. <em>Try moving extra characters to the filter field.</em><br>\n");
  440. $glimpse_error_reported = 1;
  441. last;
  442. }
  443. if ($line =~ /^[^:]*:[^:]*regular expression too long, max is (\d+)/) {
  444. print ("Regular expression pattern too long.
  445. Use a maximum of $1 characters.
  446. <em>Try moving extra characters to the filter field.</em><br>\n");
  447. $glimpse_error_reported = 1;
  448. last;
  449. }
  450. if ($line =~ /^[^:]*:[^:]*pattern '([^']*)' has no characters that were indexed/) {
  451. print ("Pattern does not include any indexed characters.
  452. <em>Try adding [a-z] as a regexp.</em><br>\n");
  453. $glimpse_error_reported = 1;
  454. last;
  455. }
  456. }
  457. next if $line =~
  458. m|using working-directory '.*' to locate dictionaries|;
  459. next if $search_sensitive && $line !~ /$search_case/;
  460. my $skip = 0;
  461. foreach $filter (@filters) {
  462. $skip = 1 unless $line =~ /$filter/;
  463. }
  464. next if $skip;
  465. my ($curr_file, undef, undef) =
  466. $line =~ /(.*?):\s*(\d+)\s*:(.*)/;
  467. my $lstyle = '';
  468. if ($prev_file ne $curr_file) {
  469. $prev_file = $curr_file;
  470. $hit_for_current_file = 1;
  471. ++$hit_file_count;
  472. if ($hit_file_count == 2) {
  473. $lstyle .= ".matches_f {display: inline;}";
  474. }
  475. $lstyle .= toggle_style($hit_file_count, 'f');
  476. } elsif (defined $hitlimit &&
  477. ++$hit_for_current_file > $hitlimit) {
  478. next LINE;
  479. }
  480. $numlines++;
  481. if ($numlines == 1) {
  482. $lstyle .= ".status.matches_one {display: block}
  483. ";
  484. } elsif ($numlines == 2) {
  485. $lstyle .= ".status.matches_one {display: none}
  486. .status.matches_n {display: block}
  487. ";
  488. } else {
  489. $lstyle .= toggle_style($numlines, 'm');
  490. }
  491. if ($numlines > $maxhits) {
  492. $lstyle .= ".status.matches_n {display: none}
  493. .status.matches_max {display: block}";
  494. }
  495. if ($lstyle) {
  496. print "$styles$lstyle$stylee";
  497. }
  498. display_line($line, $searchtext);
  499. last if $numlines > $maxhits;
  500. }
  501. my $none = $numlines == 0 ? '.status.matches_zero {display: block}' : '';
  502. print "$styles $none
  503. .status.searching {display: none}
  504. </style>";
  505. print ('</ul>') if $openlist;
  506. print "<p>";
  507. if ($numlines < 5) {
  508. close(GLIMPSE);
  509. $retval = $? >> 8;
  510. } else {
  511. kill 15, $glimpsepid;
  512. $retval = 0;
  513. }
  514. # The manpage for glimpse says that it returns 2 on syntax errors or
  515. # inaccessible files. It seems this is not the case.
  516. # We will have to work around it for the time being.
  517. if ($retval == 0) {
  518. if ($numlines == 0) {
  519. print "No matching files<br>
  520. ";
  521. } else {
  522. if ($numlines > $maxhits) {
  523. print "<b>Too many hits, displaying the first $maxhits</b>
  524. <br>";
  525. } else {
  526. if ($numlines == 1) {
  527. print "<b>Found one matching line</b>
  528. <br>";
  529. } else {
  530. my $match_count = $hitlimit != 1
  531. ? " $numlines"
  532. : '';
  533. my $in_files = $hit_file_count > 1
  534. ? " in $hit_file_count files"
  535. : '';
  536. print "<b>Found$match_count matching lines$in_files</b>
  537. <br>";
  538. }
  539. }
  540. }
  541. } elsif ($retval == 1) {
  542. print "<b>No results found</b>
  543. <br>";
  544. } elsif ($retval == 2) {
  545. # searching for '-' triggers this.
  546. } else {
  547. print "Unexpected return value $retval from Glimpse.
  548. Please file a
  549. <a href='https://bugzilla.mozilla.org/enter_bug.cgi?product=Webtools&component=MXR&short_desc=glimpse+unknown+retval&bug_file_loc=please-fill-this-in'
  550. >bug</a>
  551. ";
  552. }
  553. }
  554. }
  555. ($Conf, $HTTP, $Path, $head) = &glimpse_init;
  556. $searchtext = $HTTP->{'param'}->{'string'};
  557. $regexp = $HTTP->{'param'}->{'regexp'} || $Conf->{'regexp'};
  558. $regexp = $regexp =~ /1|on|yes/ ? 1 : '';
  559. $find = $HTTP->{'param'}->{'find'};
  560. $findi = $HTTP->{'param'}->{'findi'};
  561. $search_sensitive = defined $HTTP->{'param'}->{'case'} ? $HTTP->{'param'}->{'case'} =~ /1|on|yes/ : '';
  562. $filter = $HTTP->{'param'}->{'filter'} ||
  563. # '^[^\\0]*$'
  564. '%5E%5B%5E\\0%5D%2A%24';
  565. $hitlimit = cleanHitlimit($HTTP->{'param'}->{'hitlimit'}) || undef;
  566. $filter =~ tr/+/ /;
  567. $filter =~ s/%(\w\w)/chr(hex $1)/ge;
  568. sub cleanHitlimit {
  569. my $hitLimit = shift;
  570. $hitLimit =~ s/\D//gs;
  571. return $hitLimit;
  572. }
  573. $find_warning = 0;
  574. if (defined $findi && $findi ne '') {
  575. if (defined $find && $find ne '') {
  576. $find_warning = $find ne $findi;
  577. } else {
  578. #$find = $findi;
  579. }
  580. }
  581. sub cleanFind {
  582. my $find = shift;
  583. $find =~ s/["`'<>|()]+//g;
  584. $find =~ s|%2f|/|gi;
  585. $find =~ s|%24|\$|g;
  586. $find =~ s|%5c|\\|gi;
  587. $find =~ s|%2a|*|gi;
  588. return $find;
  589. }
  590. $find = cleanFind($find);
  591. $searchtext =~ tr/+/ /;
  592. $searchtext =~ s/%([0-9a-f]{2})/chr(hex $1)/gie;
  593. my $refresh;
  594. my $tree = $HTTP->{'param'}->{'tree'};
  595. if ($tree && ($tree ne $Conf->{'treename'})) {
  596. my @treelist = @{$Conf->{'trees'}};
  597. foreach my $othertree (@treelist) {
  598. next unless $othertree eq $tree;
  599. push @tail, "string=" . url_quote($searchtext) if $searchtext ne '';
  600. push @tail, "regexp=" . url_quote($regexp) if $regexp ne '';
  601. push @tail, "case=" . url_quote($search_sensitive) if $search_sensitive ne '';
  602. push @tail, "find=" . url_quote($find) if $find ne '';
  603. push @tail, "findi=" . url_quote($findi) if $findi ne '';
  604. push @tail, "filter=" . url_quote($filter) if $filter ne '';
  605. push @tail, "hitlimit=" . url_quote($hitlimit) if $hitlimit ne '';
  606. my $tail = $#tail >= 0 ? '?' . join "&", @tail : '';
  607. $refresh .= "Refresh: 0; url=../$tree/search$tail
  608. ";
  609. }
  610. }
  611. print "$head$refresh
  612. ";
  613. exit if $refresh ne '';
  614. &makeheader('search');
  615. &search;
  616. &makefooter('search');
  617. 1;