Classes | Macros | Functions
doxysearch.cpp File Reference
#include <cstdio>
#include <cstdlib>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <xapian.h>
#include <sys/stat.h>

Go to the source code of this file.

Classes

struct  WordPosition
 
struct  WordPosition_less
 
struct  Fragment
 
struct  Fragment_greater
 
struct  Range
 

Macros

#define FIELD_TYPE   1
 
#define FIELD_NAME   2
 
#define FIELD_ARGS   3
 
#define FIELD_TAG   4
 
#define FIELD_URL   5
 
#define FIELD_KEYW   6
 
#define FIELD_DOC   7
 
#define HEX2DEC(x)
 

Functions

bool dirExists (const std::string &dirName)
 
static std::string uriDecode (const std::string &sSrc)
 
static std::vector< std::stringsplit (const std::string &s, char delim)
 
template<class T >
fromString (const std::string &s)
 
static bool insideRange (const std::vector< Range > &ranges, int start, int len)
 
static void highlighter (const std::string &s, const std::vector< std::string > &words, std::vector< Fragment > &fragments)
 
static std::string escapeString (const std::string &s)
 
static void showError (const std::string &callback, const std::string &error)
 
int main (int argc, char **argv)
 

Macro Definition Documentation

#define FIELD_ARGS   3

Definition at line 38 of file doxysearch.cpp.

#define FIELD_DOC   7

Definition at line 42 of file doxysearch.cpp.

#define FIELD_KEYW   6

Definition at line 41 of file doxysearch.cpp.

#define FIELD_NAME   2

Definition at line 37 of file doxysearch.cpp.

#define FIELD_TAG   4

Definition at line 39 of file doxysearch.cpp.

#define FIELD_TYPE   1

Definition at line 36 of file doxysearch.cpp.

#define FIELD_URL   5

Definition at line 40 of file doxysearch.cpp.

#define HEX2DEC (   x)
Value:
(((x)>='0' && (x)<='9')?((x)-'0'):\
((x)>='a' && (x)<='f')?((x)-'a'+10):\
((x)>='A' && (x)<='F')?((x)-'A'+10):-1)
list x
Definition: train.py:276

Definition at line 44 of file doxysearch.cpp.

Function Documentation

bool dirExists ( const std::string dirName)

Definition at line 49 of file doxysearch.cpp.

50 {
51 #ifdef _WIN32
52  DWORD ftyp = GetFileAttributesA(dirName.c_str());
53  if (ftyp == INVALID_FILE_ATTRIBUTES)
54  return false; //something is wrong with your path!
55 
56  if (ftyp & FILE_ATTRIBUTE_DIRECTORY)
57  return true; // this is a directory!
58 #else
59  struct stat sb;
60 
61  if (stat(dirName.c_str(), &sb)==0 && S_ISDIR(sb.st_mode))
62  {
63  return true;
64  }
65 #endif
66 
67  return false;
68 }
static std::string escapeString ( const std::string s)
static

Escapes a string such that is can be included in a JSON structure

Definition at line 288 of file doxysearch.cpp.

289 {
290  std::stringstream dst;
291  for (unsigned int i=0;i<s.length();i++)
292  {
293  char ch = s[i];
294  switch (ch)
295  {
296  case '\"': dst << "\\\""; break;
297  default: dst << ch; break;
298  }
299  }
300  return dst.str();
301 }
uint length() const
Definition: qcstring.h:195
static QCString * s
Definition: config.cpp:1042
template<class T >
T fromString ( const std::string s)

Read type T from string s

Definition at line 132 of file doxysearch.cpp.

133 {
134  std::istringstream stream (s);
135  T t;
136  stream >> t;
137  return t;
138 }
static QCString * s
Definition: config.cpp:1042
static void highlighter ( const std::string s,
const std::vector< std::string > &  words,
std::vector< Fragment > &  fragments 
)
static

Returns a list of text fragments from s containing one or more words. The list is sorted according to the number of occurrences of words within the fragment.

Definition at line 202 of file doxysearch.cpp.

205 {
206  const std::string spanStart="<span class=\"hl\">";
207  const std::string spanEnd="</span>";
208  const std::string dots="...";
209  const int fragLen = 60;
210  int sl=s.length();
211 
212  // find positions of words in s
213  size_t j=0;
214  std::vector<WordPosition> positions;
215  for (std::vector<std::string>::const_iterator it=words.begin();
216  it!=words.end();
217  ++it,++j
218  )
219  {
220  int pos=0;
221  size_t i;
222  std::string word = *it;
223  while ((i=s.find(word,pos))!=std::string::npos)
224  {
225  positions.push_back(WordPosition(i,j));
226  pos=i+word.length();
227  }
228  }
229  // sort on position
230  std::sort(positions.begin(),positions.end(),WordPosition_less());
231  // get fragments around words
232  std::vector<Range> ranges;
233  for (std::vector<WordPosition>::const_iterator it=positions.begin();
234  it!=positions.end();
235  ++it)
236  {
237  WordPosition wp = *it;
238  std::string w = words[wp.index];
239  int i=wp.start;
240  int wl=w.length();
241  if (!insideRange(ranges,i,wl))
242  {
243  if (wl>fragLen)
244  {
245  fragments.push_back(Fragment(spanStart+w+spanEnd,1));
246  ranges.push_back(Range(i,i+wl));
247  }
248  else
249  {
250  std::string startFragment,endFragment;
251  int bi=i-(fragLen-wl)/2;
252  int ei=i+wl+(fragLen-wl)/2;
253  int occ=0;
254  if (bi<0) { ei-=bi; bi=0; } else startFragment=dots;
255  if (ei>sl) { ei=sl; } else endFragment=dots;
256  while (bi>0 && !isspace(s[bi])) bi--; // round to start of the word
257  while (ei<sl && !isspace(s[ei])) ei++; // round to end of the word
258  // highlight any word in s between indexes bi and ei
259  std::string fragment=startFragment;
260  int pos=bi;
261  for (std::vector<WordPosition>::const_iterator it2=positions.begin();
262  it2!=positions.end();
263  ++it2)
264  {
265  WordPosition wp2 = *it2;
266  std::string w2 = words[wp2.index];
267  int wl2 = w2.length();
268  if (wp2.start>=bi && wp2.start+wl2<=ei) // word is inside the range!
269  {
270  fragment+=s.substr(pos,wp2.start-pos)+
271  spanStart+
272  s.substr(wp2.start,wl2)+
273  spanEnd;
274  pos=wp2.start+wl2;
275  occ++;
276  }
277  }
278  fragment+=s.substr(pos,ei-pos)+endFragment;
279  fragments.push_back(Fragment(fragment,occ));
280  ranges.push_back(Range(bi,ei));
281  }
282  }
283  }
284  std::sort(fragments.begin(),fragments.end(),Fragment_greater());
285 }
uint length() const
Definition: qcstring.h:195
std::string string
Definition: nybbler.cc:12
intermediate_table::const_iterator const_iterator
int find(char c, int index=0, bool cs=TRUE) const
Definition: qcstring.cpp:41
static bool insideRange(const std::vector< Range > &ranges, int start, int len)
Definition: doxysearch.cpp:183
static QCString * s
Definition: config.cpp:1042
union ptb::content::word::word word
static bool insideRange ( const std::vector< Range > &  ranges,
int  start,
int  len 
)
static

Returns true if [start..start+len] is inside one of the ranges.

Definition at line 183 of file doxysearch.cpp.

184 {
185  for (std::vector<Range>::const_iterator it = ranges.begin();
186  it!=ranges.end(); ++it
187  )
188  {
189  Range r = *it;
190  if (start>=r.start && start+len<r.end)
191  {
192  return true;
193  }
194  }
195  return false;
196 }
intermediate_table::const_iterator const_iterator
int start
Definition: doxysearch.cpp:178
int end
Definition: doxysearch.cpp:179
int main ( int  argc,
char **  argv 
)

Main routine

Definition at line 310 of file doxysearch.cpp.

311 {
312  // process inputs that were passed to us via QUERY_STRING
313  std::cout << "Content-Type:application/javascript;charset=utf-8\r\n\n";
314  std::string callback;
315  try
316  {
317  // get input parameters
318  const char *queryEnv = getenv("QUERY_STRING");
319  std::string queryString;
320  if (queryEnv)
321  {
322  queryString = queryEnv;
323  }
324  else if (argc>=2)
325  {
326  queryString = argv[1];
327  }
328  else
329  {
330  std::cout << "No input!\n";
331  exit(1);
332  }
333 
334  // parse query string
335  std::vector<std::string> parts = split(queryString,'&');
336  std::string searchFor,callback;
337  int num=1,page=0;
338  for (std::vector<std::string>::const_iterator it=parts.begin();it!=parts.end();++it)
339  {
340  std::vector<std::string> kv = split(*it,'=');
341  if (kv.size()==2)
342  {
343  std::string val = uriDecode(kv[1]);
344  if (kv[0]=="q") searchFor = val;
345  else if (kv[0]=="n") num = fromString<int>(val);
346  else if (kv[0]=="p") page = fromString<int>(val);
347  else if (kv[0]=="cb") callback = val;
348  }
349  }
350 
351  std::string indexDir = "doxysearch.db";
352 
353  if (queryString=="test") // user test
354  {
355  bool dbOk = dirExists(indexDir);
356  if (dbOk)
357  {
358  std::cout << "Test successful.";
359  }
360  else
361  {
362  std::cout << "Test failed: cannot find search index " << indexDir;
363  }
364  exit(0);
365  }
366 
367  // create query
368  Xapian::Database db(indexDir);
369  Xapian::Enquire enquire(db);
370  Xapian::Query query;
371  std::vector<std::string> words = split(searchFor,' ');
372  for (std::vector<std::string>::const_iterator it=words.begin();it!=words.end();++it)
373  {
374  query = Xapian::Query(Xapian::Query::OP_OR,query,Xapian::Query(*it));
375  }
376  enquire.set_query(query);
377 
378  // get results
379  Xapian::MSet matches = enquire.get_mset(page*num,num);
380  unsigned int hits = matches.get_matches_estimated();
381  unsigned int offset = page*num;
382  unsigned int pages = num>0 ? (hits+num-1)/num : 0;
383  if (offset>hits) offset=hits;
384  if (offset+num>hits) num=hits-offset;
385 
386  // write results as JSONP
387  std::cout << callback.c_str() << "(";
388  std::cout << "{" << std::endl
389  << " \"hits\":" << hits << "," << std::endl
390  << " \"first\":" << offset << "," << std::endl
391  << " \"count\":" << num << "," << std::endl
392  << " \"page\":" << page << "," << std::endl
393  << " \"pages\":" << pages << "," << std::endl
394  << " \"query\": \"" << escapeString(searchFor) << "\"," << std::endl
395  << " \"items\":[" << std::endl;
396  // foreach search result
397  unsigned int o = offset;
398  for (Xapian::MSetIterator i = matches.begin(); i != matches.end(); ++i,++o)
399  {
400  std::vector<Fragment> hl;
401  Xapian::Document doc = i.get_document();
402  highlighter(doc.get_value(FIELD_DOC),words,hl);
403  std::cout << " {\"type\": \"" << doc.get_value(FIELD_TYPE) << "\"," << std::endl
404  << " \"name\": \"" << doc.get_value(FIELD_NAME) << escapeString(doc.get_value(FIELD_ARGS)) << "\"," << std::endl
405  << " \"tag\": \"" << doc.get_value(FIELD_TAG) << "\"," << std::endl
406  << " \"url\": \"" << doc.get_value(FIELD_URL) << "\"," << std::endl;
407  std::cout << " \"fragments\":[" << std::endl;
408  int c=0;
409  bool first=true;
410  for (std::vector<Fragment>::const_iterator it = hl.begin();it!=hl.end() && c<3;++it,++c)
411  {
412  if (!first) std::cout << "," << std::endl;
413  std::cout << " \"" << escapeString((*it).text) << "\"";
414  first=false;
415  }
416  if (!first) std::cout << std::endl;
417  std::cout << " ]" << std::endl;
418  std::cout << " }";
419  if (o<offset+num-1) std::cout << ",";
420  std::cout << std::endl;
421  }
422  std::cout << " ]" << std::endl << "})" << std::endl;
423  }
424  catch (const Xapian::Error &e) // Xapian exception
425  {
426  showError(callback,e.get_description());
427  }
428  catch (...) // Any other exception
429  {
430  showError(callback,"Unknown Exception!");
431  exit(1);
432  }
433  return 0;
434 }
static std::string escapeString(const std::string &s)
Definition: doxysearch.cpp:288
#define FIELD_URL
Definition: doxysearch.cpp:40
#define FIELD_TAG
Definition: doxysearch.cpp:39
std::string string
Definition: nybbler.cc:12
#define FIELD_TYPE
Definition: doxysearch.cpp:36
intermediate_table::const_iterator const_iterator
#define FIELD_ARGS
Definition: doxysearch.cpp:38
static void highlighter(const std::string &s, const std::vector< std::string > &words, std::vector< Fragment > &fragments)
Definition: doxysearch.cpp:202
static std::string uriDecode(const std::string &sSrc)
Definition: doxysearch.cpp:72
const double e
nvidia::inferenceserver::client::Error Error
Definition: triton_utils.h:15
std::string getenv(std::string const &name)
Definition: getenv.cc:15
static std::vector< std::string > split(const std::string &s, char delim)
Definition: doxysearch.cpp:121
static void showError(const std::string &callback, const std::string &error)
Definition: doxysearch.cpp:303
bool dirExists(const std::string &dirName)
Definition: doxysearch.cpp:49
QCString doc
#define FIELD_NAME
Definition: doxysearch.cpp:37
query_result< Args... > query(sqlite3 *db, std::string const &ddl)
Definition: select.h:75
#define FIELD_DOC
Definition: doxysearch.cpp:42
QTextStream & endl(QTextStream &s)
static void showError ( const std::string callback,
const std::string error 
)
static

Definition at line 303 of file doxysearch.cpp.

304 {
305  std::cout << callback << "({\"error\":\"" << error << "\"})";
306  exit(0);
307 }
error
Definition: include.cc:26
static std::vector<std::string> split ( const std::string s,
char  delim 
)
static

return list of strings that result when splitting s using delimiter delim

Definition at line 121 of file doxysearch.cpp.

122 {
123  std::vector<std::string> elems;
124  std::stringstream ss(s);
125  std::string item;
126  while (getline(ss, item, delim)) elems.push_back(item);
127  return elems;
128 }
string delim()
Definition: fcldump.cxx:40
std::string string
Definition: nybbler.cc:12
static QCString * s
Definition: config.cpp:1042
static std::string uriDecode ( const std::string sSrc)
static

decodes a URI encoded string into a normal string.

Definition at line 72 of file doxysearch.cpp.

73 {
74  // Note from RFC1630: "Sequences which start with a percent
75  // sign but are not followed by two hexadecimal characters
76  // (0-9, A-F) are reserved for future extension"
77 
78  const unsigned char * pSrc = (const unsigned char *)sSrc.c_str();
79  const int SRC_LEN = sSrc.length();
80  const unsigned char * const SRC_END = pSrc + SRC_LEN;
81  // last decodable '%'
82  const unsigned char * const SRC_LAST_DEC = SRC_END - 2;
83 
84  char * const pStart = new char[SRC_LEN];
85  char * pEnd = pStart;
86 
87  while (pSrc < SRC_LAST_DEC)
88  {
89  if (*pSrc == '%') // replace %2A with corresponding ASCII character
90  {
91  char dec1, dec2;
92  unsigned char c1=*(pSrc+1);
93  unsigned char c2=*(pSrc+2);
94  if (-1 != (dec1 = HEX2DEC(c1))
95  && -1 != (dec2 = HEX2DEC(c2)))
96  {
97  *pEnd++ = (dec1 << 4) + dec2;
98  pSrc += 3;
99  continue;
100  }
101  }
102  else if (*pSrc == '+') // replace '+' with space
103  {
104  *pEnd++ = ' '; pSrc++;
105  continue;
106  }
107  *pEnd++ = *pSrc++;
108  }
109 
110  // the last 2- chars
111  while (pSrc < SRC_END) *pEnd++ = *pSrc++;
112 
113  std::string sResult(pStart, pEnd);
114  delete [] pStart;
115  return sResult;
116 }
std::string string
Definition: nybbler.cc:12
#define HEX2DEC(x)
Definition: doxysearch.cpp:44