added search engine
tho [Fri, 13 Apr 2007 10:56:46 +0000 (10:56 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@225 270642c3-0616-0410-b53a-bc976706d245

Examples/Mainpage.dox
doclib/Doxyfile.global
doclib/doxy-header-overview.html
doclib/doxy-header.html
doclib/html-munge.xsl
doclib/search.php [new file with mode: 0644]
doclib/search_functions.php [new file with mode: 0644]
doclib/senf.css

index 002b0e1..f8ef7eb 100644 (file)
@@ -62,6 +62,8 @@
     specific type of socket which returns ethernet packets directly from the network wire. By
     uncommenting the last line, you may switch the interface into promiscuous mode.
 
+    \until //
+
     We will now read packets from the socket forever, that is until the user hits Ctrl-C
 
     \skip while
 
     \see \ref components \n
          \ref build \n
-         <a href="../../Socket/doc/html/index.html"><b>libSocket API reference</b></a> \n
-         <a href="../../Packets/doc/html/index.html"><b>libPackets API reference</b></a> \n
-         <a href="../../Utils/doc/html/index.html"><b>libUtils API reference</b></a>
+         <a href="../../../Socket/doc/html/index.html"><b>libSocket API reference</b></a> \n
+         <a href="../../../Packets/doc/html/index.html"><b>libPackets API reference</b></a> \n
+         <a href="../../../Utils/doc/html/index.html"><b>libUtils API reference</b></a>
  */
 
 
index b959702..5d8dbba 100644 (file)
@@ -21,6 +21,7 @@ INTERNAL_DOCS          = YES
 SOURCE_BROWSER         = YES
 ALPHABETICAL_INDEX     = YES
 COLS_IN_ALPHA_INDEX    = 3
+SEARCHENGINE           = YES
 
 MACRO_EXPANSION        = YES
 EXPAND_ONLY_PREDEF     = YES
index 9a4bf37..050cc2b 100644 (file)
@@ -13,6 +13,11 @@ div.tabs ul li.$projectname a { background-color: #EDE497; }
 <div id="head">
   <h1>SENF Extensible Network Framework</h1>
   <h2>Introduction and Overview</h2>
+  <div id="search">
+    <form action="../../doclib/search.php" method="get">
+      Search: <input type="text" name="query" size="20" accesskey="s"/> 
+    </form>
+  </div>
 </div>
 
 <div id="content1">
index b3499de..ba83bb6 100644 (file)
@@ -13,6 +13,11 @@ div.tabs ul li.$projectname a { background-color: #EDE497; }
 <div id="head">
   <h1>SENF Extensible Network Framework</h1>
   <h2>Documentation and API reference</h2>
+  <div id="search">
+    <form action="../../../doclib/search.php" method="get">
+      Search: <input type="text" name="query" size="20" accesskey="s"/> 
+    </form>
+  </div>
 </div>
 
 <div id="content1">
index 341275b..a7f17c3 100644 (file)
@@ -10,6 +10,9 @@
     </xsl:copy>\r
   </xsl:template>\r
   \r
+  <xsl:template match="li[form]"> \r
+  </xsl:template>\r
+  \r
   <!-- Add 'class' attribute to some special paragraphs/lists -->\r
   \r
   <xsl:template name="add-class">\r
@@ -74,5 +77,5 @@
       <xsl:with-param name="class">anchor</xsl:with-param>\r
     </xsl:call-template>\r
   </xsl:template>\r
-\r
+  \r
 </xsl:stylesheet>\r
diff --git a/doclib/search.php b/doclib/search.php
new file mode 100644 (file)
index 0000000..7fc04f5
--- /dev/null
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Search</title>
+<link href="../doc/html/doxygen.css" rel="stylesheet" type="text/css">
+<link href="senf.css" rel="stylesheet" type="text/css">
+<?php include 'search_functions.php'; ?>
+</head>
+<body>
+
+<div id="head">
+  <h1>SENF Extensible Network Framework</h1>
+  <h2>Search Results</h2>
+  <div id="search">
+    <form action="search.php" method="get">
+    Search: <?php inputfield(); ?>
+    </form>
+  </div>
+</div>
+
+<div id="content1">
+  <div id="content2">
+    <div class="tabs menu">
+      <ul>
+        <li class="Overview"><a href="../doc/html/index.html">Overview</a></li>
+        <li class="libSocket"><a href="../Socket/doc/html/index.html">libSocket</a></li>
+        <li class="libPackets"><a href="../Packets/doc/html/index.html">libPackets</a></li>
+        <li class="libScheduler"><a href="../Scheduler/doc/html/index.html">libScheduler</a></li>
+        <li class="libUtils"><a href="../Utils/doc/html/index.html">libUtils</a></li>
+        <li class="Examples"><a href="../Examples/doc/html/index.html">Examples</a></li>
+        <li class="SENFSCons"><a href="../senfscons/doc/html/index.html">SENFSCons</a></li>
+      </ul>
+    </div>
+
+    <div class="tabs">
+      <ul>
+        <li><a href="xref.html">Open Issues</a></li>
+        <li><a href="http://svn.berlios.de/wsvn/senf/?op=log&rev=0&sc=0&isdir=1">SVN ChangeLog</a></li>
+        <li><a href="http://developer.berlios.de/projects/senf">SENF @ BerliOS</a></li>
+        <li><a href="http://openfacts.berlios.de/index-en.phtml?title=SENF+Network+Framework">Wiki</a></li>
+      </ul>
+    </div>
+  
+    <!-- Generated by Doxygen 1.4.7 -->
+    <div class="tabs">
+      <ul>
+        <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+        <li><a href="pages.html"><span>Related&nbsp;Pages</span></a></li>
+      <hr style="width:0px;border:none;clear:both;margin:0;padding:0" />
+    </div>
+
+    <?php search(); ?>
+
+    <hr style="width:0px;border:none;clear:both;margin:0;padding:0" />
+  </div>
+</div>
+<div id="footer">
+  <span>
+    <a href="mailto:senf-dev@lists.berlios.de">Contact: senf-dev@lists.berlios.de</a> |
+    Copyright &copy; 2006 Fraunhofer Gesellschaft, SatCom, Stefan Bund
+  </span>
+</div>
+
+</body></html>
diff --git a/doclib/search_functions.php b/doclib/search_functions.php
new file mode 100644 (file)
index 0000000..0431d0c
--- /dev/null
@@ -0,0 +1,381 @@
+<?php
+
+function search_results()
+{
+  return "Search Results";
+}
+
+function matches_text($num)
+{
+  if ($num==0)
+  {
+    return "Sorry, no documents matching your query.";
+  }
+  else if ($num==1)
+  {
+    return "Found <b>1</b> document matching your query.";
+  }
+  else // $num>1
+  {
+    return "Found <b>$num</b> documents matching your query. Showing best matches first.";
+  }
+}
+
+function report_matches()
+{
+  return "Matches: ";
+}
+function inputfield()
+{
+  $query="";
+  if (array_key_exists("query", $_GET))
+  {
+    $query=$_GET["query"];
+  }
+  echo "<input type=\"text\" name=\"query\" value=\"$query\" size=\"20\" accesskey=\"s\"/>";
+}
+
+function readInt($file)
+{
+  $b1 = ord(fgetc($file)); $b2 = ord(fgetc($file));
+  $b3 = ord(fgetc($file)); $b4 = ord(fgetc($file));
+  return ($b1<<24)|($b2<<16)|($b3<<8)|$b4;
+}
+
+function readString($file)
+{
+  $result="";
+  while (ord($c=fgetc($file))) $result.=$c;
+  return $result;
+}
+
+function readHeader($file)
+{
+  $header =fgetc($file); $header.=fgetc($file);
+  $header.=fgetc($file); $header.=fgetc($file);
+  return $header;
+}
+
+function computeIndex($word)
+{
+  // Fast string hashing
+  //$lword = strtolower($word);
+  //$l = strlen($lword);
+  //for ($i=0;$i<$l;$i++)
+  //{
+  //  $c = ord($lword{$i});
+  //  $v = (($v & 0xfc00) ^ ($v << 6) ^ $c) & 0xffff;
+  //}
+  //return $v;
+
+  // Simple hashing that allows for substring search
+  if (strlen($word)<2) return -1;
+  // high char of the index
+  $hi = ord($word{0});
+  if ($hi==0) return -1;
+  // low char of the index
+  $lo = ord($word{1});
+  if ($lo==0) return -1;
+  // return index
+  return $hi*256+$lo;
+}
+
+function do_search($path, $file,$word,&$statsList)
+{
+  $index = computeIndex($word);
+  if ($index!=-1) // found a valid index
+  {
+    fseek($file,$index*4+4); // 4 bytes per entry, skip header
+    $index = readInt($file);
+    if ($index) // found words matching the hash key
+    {
+      $start=sizeof($statsList);
+      $count=$start;
+      fseek($file,$index);
+      $w = readString($file);
+      while ($w)
+      {
+        $statIdx = readInt($file);
+        if ($word==substr($w,0,strlen($word)))
+        { // found word that matches (as substring)
+          $statsList[$count++]=array(
+              "word"=>$word,
+              "match"=>$w,
+              "index"=>$statIdx,
+              "full"=>strlen($w)==strlen($word),
+              "docs"=>array()
+              );
+        }
+        $w = readString($file);
+      }
+      $totalHi=0;
+      $totalFreqHi=0;
+      $totalFreqLo=0;
+      for ($count=$start;$count<sizeof($statsList);$count++)
+      {
+        $statInfo = &$statsList[$count];
+        $multiplier = 1;
+        // whole word matches have a double weight
+        if ($statInfo["full"]) $multiplier=2;
+        fseek($file,$statInfo["index"]); 
+        $numDocs = readInt($file);
+        $docInfo = array();
+        // read docs info + occurrence frequency of the word
+        for ($i=0;$i<$numDocs;$i++)
+        {
+          $idx=readInt($file); 
+          $freq=readInt($file); 
+          $docInfo[$i]=array("idx"  => $idx,
+                             "freq" => $freq>>1,
+                             "rank" => 0.0,
+                             "hi"   => $freq&1
+                            );
+          if ($freq&1) // word occurs in high priority doc
+          {
+            $totalHi++;
+            $totalFreqHi+=$freq*$multiplier;
+          }
+          else // word occurs in low priority doc
+          {
+            $totalFreqLo+=$freq*$multiplier;
+          }
+        }
+        // read name and url info for the doc
+        for ($i=0;$i<$numDocs;$i++)
+        {
+          fseek($file,$docInfo[$i]["idx"]);
+          $docInfo[$i]["name"]=readString($file);
+          $docInfo[$i]["url"]=$path.readString($file);
+        }
+        $statInfo["docs"]=$docInfo;
+      }
+      $totalFreq=($totalHi+1)*$totalFreqLo + $totalFreqHi;
+      for ($count=$start;$count<sizeof($statsList);$count++)
+      {
+        $statInfo = &$statsList[$count];
+        $multiplier = 1;
+        // whole word matches have a double weight
+        if ($statInfo["full"]) $multiplier=2;
+        for ($i=0;$i<sizeof($statInfo["docs"]);$i++)
+        {
+          $docInfo = &$statInfo["docs"];
+          // compute frequency rank of the word in each doc
+          $freq=$docInfo[$i]["freq"];
+          if ($docInfo[$i]["hi"])
+          {
+            $statInfo["docs"][$i]["rank"]=
+              (float)($freq*$multiplier+$totalFreqLo)/$totalFreq;
+          }
+          else
+          {
+            $statInfo["docs"][$i]["rank"]=
+              (float)($freq*$multiplier)/$totalFreq;
+          }
+        }
+      }
+    }
+  }
+  return $statsList;
+}
+
+function combine_results($results,&$docs)
+{
+  foreach ($results as $wordInfo)
+  {
+    $docsList = &$wordInfo["docs"];
+    foreach ($docsList as $di)
+    {
+      $key=$di["url"];
+      $rank=$di["rank"];
+      if (in_array($key, array_keys($docs)))
+      {
+        $docs[$key]["rank"]+=$rank;
+      }
+      else
+      {
+        $docs[$key] = array("url"=>$key,
+            "name"=>$di["name"],
+            "rank"=>$rank
+            );
+      }
+      $docs[$key]["words"][] = array(
+               "word"=>$wordInfo["word"],
+               "match"=>$wordInfo["match"],
+               "freq"=>$di["freq"]
+               );
+    }
+  }
+  return $docs;
+}
+
+function filter_results($docs,&$requiredWords,&$forbiddenWords)
+{
+  $filteredDocs=array();
+  while (list ($key, $val) = each ($docs)) 
+  {
+    $words = &$docs[$key]["words"];
+    $copy=1; // copy entry by default
+    if (sizeof($requiredWords)>0)
+    {
+      foreach ($requiredWords as $reqWord)
+      {
+        $found=0;
+        foreach ($words as $wordInfo)
+        { 
+          $found = $wordInfo["word"]==$reqWord;
+          if ($found) break;
+        }
+        if (!$found) 
+        {
+          $copy=0; // document contains none of the required words
+          break;
+        }
+      }
+    }
+    if (sizeof($forbiddenWords)>0)
+    {
+      foreach ($words as $wordInfo)
+      {
+        if (in_array($wordInfo["word"],$forbiddenWords))
+        {
+          $copy=0; // document contains a forbidden word
+          break;
+        }
+      }
+    }
+    if ($copy) $filteredDocs[$key]=$docs[$key];
+  }
+  return $filteredDocs;
+}
+
+function compare_rank($a,$b)
+{
+  if ($a["rank"] == $b["rank"]) 
+  {
+    return 0;
+  }
+  return ($a["rank"]>$b["rank"]) ? -1 : 1; 
+}
+
+function sort_results($docs,&$sorted)
+{
+  $sorted = $docs;
+  usort($sorted,"compare_rank");
+  return $sorted;
+}
+
+function report_results(&$docs)
+{
+  echo "<table cellspacing=\"2\">\n";
+  echo "  <tr>\n";
+  echo "    <td colspan=\"2\"><h2>".search_results()."</h2></td>\n";
+  echo "  </tr>\n";
+  $numDocs = sizeof($docs);
+  if ($numDocs==0)
+  {
+    echo "  <tr>\n";
+    echo "    <td colspan=\"2\">".matches_text(0)."</td>\n";
+    echo "  </tr>\n";
+  }
+  else
+  {
+    echo "  <tr>\n";
+    echo "    <td colspan=\"2\">".matches_text($numDocs);
+    echo "\n";
+    echo "    </td>\n";
+    echo "  </tr>\n";
+    $num=1;
+    foreach ($docs as $doc)
+    {
+      echo "  <tr>\n";
+      echo "    <td align=\"right\">$num.</td>";
+      echo     "<td><a class=\"el\" href=\"".$doc["url"]."\">".$doc["name"]."</a></td>\n";
+      echo "  <tr>\n";
+      echo "    <td></td><td class=\"tiny\">".report_matches()." ";
+      foreach ($doc["words"] as $wordInfo)
+      {
+        $word = $wordInfo["word"];
+        $matchRight = substr($wordInfo["match"],strlen($word));
+        echo "<b>$word</b>$matchRight(".$wordInfo["freq"].") ";
+      }
+      echo "    </td>\n";
+      echo "  </tr>\n";
+      $num++;
+    }
+  }
+  echo "</table>\n";
+}
+
+function search()
+{
+  if(strcmp('4.1.0', phpversion()) > 0) 
+  {
+    die("Error: PHP version 4.1.0 or above required!");
+  }
+
+  $paths = array(
+       "../doc/html/", 
+    "../Socket/doc/html/",
+    "../Examples/doc/html/",
+    "../Packets/doc/html/",
+    "../Utils/doc/html/",
+    "../Scheduler/doc/html/",
+  );
+  $files = array();
+  $j=0;
+  for ($i=0; $i<sizeof($paths); $i++) {
+       if (!($f=@fopen($paths[$i]."search.idx","rb"))) 
+    {
+      die("Error: Search index file could NOT be opened!");
+      continue;
+    }
+    $files[$j++] = $f;
+    if (readHeader($f)!="DOXS")
+    {
+      die("Error: Header of index file is invalid!");
+    }
+  }
+  $query="";
+  if (array_key_exists("query", $_GET))
+  {
+    $query=$_GET["query"];
+  }
+  //end_form($query);
+  echo "&nbsp;\n<div class=\"searchresults\">\n";
+  $results = array();
+  $requiredWords = array();
+  $forbiddenWords = array();
+  $foundWords = array();
+  $word=strtok($query," ");
+  while ($word) // for each word in the search query
+  {
+    if (($word{0}=='+')) { $word=substr($word,1); $requiredWords[]=$word; }
+    if (($word{0}=='-')) { $word=substr($word,1); $forbiddenWords[]=$word; }
+    if (!in_array($word,$foundWords))
+    {
+      $foundWords[]=$word;
+      for ($i=0; $i<sizeof($files); $i++) {
+        do_search($paths[$i], $files[$i], strtolower($word), $results);
+      }
+    }
+    $word=strtok(" ");
+  }
+  $docs = array();
+  combine_results($results,$docs);
+  // filter out documents with forbidden word or that do not contain
+  // required words
+  $filteredDocs = filter_results($docs,$requiredWords,$forbiddenWords);
+  // sort the results based on rank
+  $sorted = array();
+  sort_results($filteredDocs,$sorted);
+  // report results to the user
+  report_results($sorted);
+  echo "</div>\n";
+  foreach ($files as $file) {
+    fclose($file);
+  }
+}
+
+
+?>
index d8292be..5e3c480 100644 (file)
@@ -5,7 +5,7 @@ body {
 }
 
 #head {
-        height: 62px;
+        height: 72px;
         border-top: 5px solid #DECD40;
         border-bottom: 1px solid #AF9D00;
         background: url(logo-head.png) top left no-repeat;
@@ -27,8 +27,8 @@ body {
 
 #head h2 {
         margin: 0 0 0 100px;
-        padding: 4px 0 0 42px;
-        height: 18px;
+        padding: 6px 0 0 42px;
+        height: 26px;
         background-color: #EDE497;
         color: #726921;
         font-size: 13px;
@@ -36,6 +36,12 @@ body {
         white-space: nowrap;
 }
 
+#search {
+        position: absolute;
+        top: 50px;
+        right: 10px;
+}
+
 #content1 {
         padding: 0 10px 10px 0;
         border-bottom: 1px solid #AF9D00;