Fix for UBSan build
[platform/upstream/doxygen.git] / src / search_functions.php
1 <script language="PHP">
2 require_once "search-config.php";
3
4 function end_form($value)
5 {
6   global $config;
7   global $translator;
8   if ($config['DISABLE_INDEX'] == false)
9   {
10   echo "            <input type=\"text\" id=\"MSearchField\" name=\"query\" value=\"$value\" size=\"20\" accesskey=\"S\" onfocus=\"searchBox.OnSearchFieldFocus(true)\" onblur=\"searchBox.OnSearchFieldFocus(false)\"/>\n            </form>\n          </div><div class=\"right\"></div>\n        </div>\n      </li>\n    </ul>\n  </div>\n</div>\n";
11   }
12   if ($config['GENERATE_TREEVIEW'])
13   {
14     echo $translator['split_bar'];
15   }
16 }
17
18 function end_page()
19 {
20   //global $config;
21   //global $translator;
22   //if ($config['GENERATE_TREEVIEW'])
23   //{
24   //  echo "</div>\n<div id=\"nav-path\" class=\"navpath\">\n  <ul>\n    <li class=\"footer\">";
25   //  echo $translator['logo'];
26   //  echo "</li>\n  </ul>\n</div>";
27   //}
28   echo "</body></html>";
29 }
30
31 function search_results()
32 {
33   global $translator;
34   return $translator['search_results_title'];
35 }
36
37 function matches_text($num)
38 {
39   global $translator;
40   $string = $translator['search_results'][($num>2)?2:$num];
41   // The eval is used so that translator strings can contain $num.
42   eval("\$result = \"$string\";");
43   return $result;
44 }
45
46 function report_matches()
47 {
48   global $translator;
49   return $translator['search_matches'];
50 }
51
52 function readInt($file)
53 {
54   $b1 = ord(fgetc($file)); $b2 = ord(fgetc($file));
55   $b3 = ord(fgetc($file)); $b4 = ord(fgetc($file));
56   return ($b1<<24)|($b2<<16)|($b3<<8)|$b4;
57 }
58
59 function readString($file)
60 {
61   $result="";
62   while (ord($c=fgetc($file))) $result.=$c;
63   return $result;
64 }
65
66 function readHeader($file)
67 {
68   $header =fgetc($file); $header.=fgetc($file);
69   $header.=fgetc($file); $header.=fgetc($file);
70   return $header;
71 }
72
73 function computeIndex($word)
74 {
75   // Simple hashing that allows for substring search
76   if (strlen($word)<2) return -1;
77   // high char of the index
78   $hi = ord($word{0});
79   if ($hi==0) return -1;
80   // low char of the index
81   $lo = ord($word{1});
82   if ($lo==0) return -1;
83   // return index
84   return $hi*256+$lo;
85 }
86
87 function search($file,$word,&$statsList)
88 {
89   $index = computeIndex($word);
90   if ($index!=-1) // found a valid index
91   {
92     fseek($file,$index*4+4); // 4 bytes per entry, skip header
93     $index = readInt($file);
94     if ($index) // found words matching the hash key
95     {
96       $start=sizeof($statsList);
97       $count=$start;
98       fseek($file,$index);
99       $w = readString($file);
100       while ($w)
101       {
102         $statIdx = readInt($file);
103         if ($word==substr($w,0,strlen($word)))
104         { // found word that matches (as substring)
105           $statsList[$count++]=array(
106               "word"=>$word,
107               "match"=>$w,
108               "index"=>$statIdx,
109               "full"=>strlen($w)==strlen($word),
110               "docs"=>array()
111               );
112         }
113         $w = readString($file);
114       }
115       $totalHi=0;
116       $totalFreqHi=0;
117       $totalFreqLo=0;
118       for ($count=$start;$count<sizeof($statsList);$count++)
119       {
120         $statInfo = &$statsList[$count];
121         $multiplier = 1;
122         // whole word matches have a double weight
123         if ($statInfo["full"]) $multiplier=2;
124         fseek($file,$statInfo["index"]); 
125         $numDocs = readInt($file);
126         $docInfo = array();
127         // read docs info + occurrence frequency of the word
128         for ($i=0;$i<$numDocs;$i++)
129         {
130           $idx=readInt($file); 
131           $freq=readInt($file); 
132           $docInfo[$i]=array("idx"  => $idx,
133                              "freq" => $freq>>1,
134                              "rank" => 0.0,
135                              "hi"   => $freq&1
136                             );
137           if ($freq&1) // word occurs in high priority doc
138           {
139             $totalHi++;
140             $totalFreqHi+=$freq*$multiplier;
141           }
142           else // word occurs in low priority doc
143           {
144             $totalFreqLo+=$freq*$multiplier;
145           }
146         }
147         // read name and url info for the doc
148         for ($i=0;$i<$numDocs;$i++)
149         {
150           fseek($file,$docInfo[$i]["idx"]);
151           $docInfo[$i]["name"]=readString($file);
152           $docInfo[$i]["url"]=readString($file);
153         }
154         $statInfo["docs"]=$docInfo;
155       }
156       $totalFreq=($totalHi+1)*$totalFreqLo + $totalFreqHi;
157       for ($count=$start;$count<sizeof($statsList);$count++)
158       {
159         $statInfo = &$statsList[$count];
160         $multiplier = 1;
161         // whole word matches have a double weight
162         if ($statInfo["full"]) $multiplier=2;
163         for ($i=0;$i<sizeof($statInfo["docs"]);$i++)
164         {
165           $docInfo = &$statInfo["docs"];
166           // compute frequency rank of the word in each doc
167           $freq=$docInfo[$i]["freq"];
168           if ($docInfo[$i]["hi"])
169           {
170             $statInfo["docs"][$i]["rank"]=
171               (float)($freq*$multiplier+$totalFreqLo)/$totalFreq;
172           }
173           else
174           {
175             $statInfo["docs"][$i]["rank"]=
176               (float)($freq*$multiplier)/$totalFreq;
177           }
178         }
179       }
180     }
181   }
182   return $statsList;
183 }
184
185 function combine_results($results,&$docs)
186 {
187   foreach ($results as $wordInfo)
188   {
189     $docsList = &$wordInfo["docs"];
190     foreach ($docsList as $di)
191     {
192       $key=$di["url"];
193       $rank=$di["rank"];
194       if (isset($docs[$key]))
195       {
196         $docs[$key]["rank"]+=$rank;
197       }
198       else
199       {
200         $docs[$key] = array("url"=>$key,
201             "name"=>$di["name"],
202             "rank"=>$rank
203             );
204       }
205       $docs[$key]["words"][] = array(
206                "word"=>$wordInfo["word"],
207                "match"=>$wordInfo["match"],
208                "freq"=>$di["freq"]
209                );
210     }
211   }
212   return $docs;
213 }
214
215 function filter_results($docs,&$requiredWords,&$forbiddenWords)
216 {
217   $filteredDocs=array();
218   while (list ($key, $val) = each ($docs)) 
219   {
220     $words = &$docs[$key]["words"];
221     $copy=1; // copy entry by default
222     if (sizeof($requiredWords)>0)
223     {
224       foreach ($requiredWords as $reqWord)
225       {
226         $found=0;
227         foreach ($words as $wordInfo)
228         { 
229           $found = $wordInfo["word"]==$reqWord;
230           if ($found) break;
231         }
232         if (!$found) 
233         {
234           $copy=0; // document contains none of the required words
235           break;
236         }
237       }
238     }
239     if (sizeof($forbiddenWords)>0)
240     {
241       foreach ($words as $wordInfo)
242       {
243         if (in_array($wordInfo["word"],$forbiddenWords))
244         {
245           $copy=0; // document contains a forbidden word
246           break;
247         }
248       }
249     }
250     if ($copy) $filteredDocs[$key]=$docs[$key];
251   }
252   return $filteredDocs;
253 }
254
255 function compare_rank($a,$b)
256 {
257   if ($a["rank"] == $b["rank"]) 
258   {
259     return 0;
260   }
261   return ($a["rank"]>$b["rank"]) ? -1 : 1; 
262 }
263
264 function sort_results($docs,&$sorted)
265 {
266   $sorted = $docs;
267   usort($sorted,"compare_rank");
268   return $sorted;
269 }
270
271 function report_results(&$docs)
272 {
273   echo "<div class=\"header\">";
274   echo "  <div class=\"headertitle\">\n";
275   echo "    <h1>".search_results()."</h1>\n";
276   echo "  </div>\n";
277   echo "</div>\n";
278   echo "<div class=\"searchresults\">\n";
279   echo "<table cellspacing=\"2\">\n";
280   $numDocs = sizeof($docs);
281   if ($numDocs==0)
282   {
283     echo "  <tr>\n";
284     echo "    <td colspan=\"2\">".matches_text(0)."</td>\n";
285     echo "  </tr>\n";
286   }
287   else
288   {
289     echo "  <tr>\n";
290     echo "    <td colspan=\"2\">".matches_text($numDocs);
291     echo "\n";
292     echo "    </td>\n";
293     echo "  </tr>\n";
294     $num=1;
295     foreach ($docs as $doc)
296     {
297       echo "  <tr>\n";
298       echo "    <td align=\"right\">$num.</td>";
299       echo     "<td><a class=\"el\" href=\"".$doc["url"]."\">".$doc["name"]."</a></td>\n";
300       echo "  <tr>\n";
301       echo "    <td></td><td class=\"tiny\">".report_matches()." ";
302       foreach ($doc["words"] as $wordInfo)
303       {
304         $word = $wordInfo["word"];
305         $matchRight = substr($wordInfo["match"],strlen($word));
306         echo "<b>$word</b>$matchRight(".$wordInfo["freq"].") ";
307       }
308       echo "    </td>\n";
309       echo "  </tr>\n";
310       $num++;
311     }
312   }
313   echo "</table>\n";
314   echo "</div>\n";
315 }
316
317 function run_query($query)
318 {
319   if(strcmp('4.1.0', phpversion()) > 0) 
320   {
321     die("Error: PHP version 4.1.0 or above required!");
322   }
323   if (!($file=fopen("search/search.idx","rb"))) 
324   {
325     die("Error: Search index file could NOT be opened!");
326   }
327   if (readHeader($file)!="DOXS")
328   {
329     die("Error: Header of index file is invalid!");
330   }
331   $results = array();
332   $requiredWords = array();
333   $forbiddenWords = array();
334   $foundWords = array();
335   $word=strtok($query," ");
336   while ($word) // for each word in the search query
337   {
338     if (($word{0}=='+')) { $word=substr($word,1); $requiredWords[]=$word; }
339     if (($word{0}=='-')) { $word=substr($word,1); $forbiddenWords[]=$word; }
340     if (!in_array($word,$foundWords))
341     {
342       $foundWords[]=$word;
343       search($file,strtolower($word),$results);
344     }
345     $word=strtok(" ");
346   }
347   fclose($file);
348   $docs = array();
349   combine_results($results,$docs);
350   // filter out documents with forbidden word or that do not contain
351   // required words
352   $filteredDocs = filter_results($docs,$requiredWords,$forbiddenWords);
353   // sort the results based on rank
354   $sorted = array();
355   sort_results($filteredDocs,$sorted);
356   return $sorted;
357 }
358
359 function main()
360 {
361   $query = "";
362   if (array_key_exists("query", $_GET))
363   {
364     $query=$_GET["query"];
365   }
366   $sorted = run_query($query);
367   // Now output the HTML stuff...
368   // End the HTML form
369   end_form(preg_replace("/[^a-zA-Z0-9\-\_\.]/i", " ", $query ));
370   // report results to the user
371   report_results($sorted);
372   end_page();
373 }
374 </script>