00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <config.h>
00022
00023 #include <xapian.h>
00024
00025 #include <cstdlib>
00026 #include <cstring>
00027
00028 #include <iostream>
00029
00030 #include "gnu_getopt.h"
00031
00032 using namespace std;
00033
00034 #define PROG_NAME "quest"
00035 #define PROG_DESC "Xapian command line search tool"
00036
00037
00038 static const char * sw[] = {
00039 "a", "about", "an", "and", "are", "as", "at",
00040 "be", "by",
00041 "en",
00042 "for", "from",
00043 "how",
00044 "i", "in", "is", "it",
00045 "of", "on", "or",
00046 "that", "the", "this", "to",
00047 "was", "what", "when", "where", "which", "who", "why", "will", "with"
00048 };
00049
00050 static void show_usage() {
00051 cout << "Usage: "PROG_NAME" [OPTIONS] 'QUERY'\n"
00052 "NB: QUERY should be quoted to protect it from the shell.\n\n"
00053 "Options:\n"
00054 " -d, --db=DIRECTORY database to search (multiple databases may be specified)\n"
00055 " -m, --msize=MSIZE maximum number of matches to return\n"
00056 " -s, --stemmer=LANG set the stemming language, the default is 'english'\n"
00057 " (pass 'none' to disable stemming)\n"
00058 " -p, --prefix=PFX:TERMPFX Add a prefix\n"
00059 " -b, --boolean-prefix=PFX:TERMPFX Add a boolean prefix\n"
00060 " -h, --help display this help and exit\n"
00061 " -v, --version output version information and exit\n";
00062 }
00063
00064 int
00065 main(int argc, char **argv)
00066 try {
00067 const char * opts = "d:m:s:p:b:hv";
00068 static const struct option long_opts[] = {
00069 { "db", required_argument, 0, 'd' },
00070 { "msize", required_argument, 0, 'm' },
00071 { "stemmer", required_argument, 0, 's' },
00072 { "prefix", required_argument, 0, 'p' },
00073 { "boolean-prefix", required_argument, 0, 'b' },
00074 { "help", no_argument, 0, 'h' },
00075 { "version", no_argument, 0, 'v' },
00076 { NULL, 0, 0, 0}
00077 };
00078
00079 Xapian::SimpleStopper mystopper(sw, sw + sizeof(sw) / sizeof(sw[0]));
00080 Xapian::Stem stemmer("english");
00081 int msize = 10;
00082
00083 bool have_database = false;
00084
00085 Xapian::Database db;
00086 Xapian::QueryParser parser;
00087
00088 int c;
00089 while ((c = gnu_getopt_long(argc, argv, opts, long_opts, 0)) != -1) {
00090 switch (c) {
00091 case 'm':
00092 msize = atoi(optarg);
00093 break;
00094 case 'd':
00095 db.add_database(Xapian::Database(optarg));
00096 have_database = true;
00097 break;
00098 case 's':
00099 try {
00100 stemmer = Xapian::Stem(optarg);
00101 } catch (const Xapian::InvalidArgumentError &) {
00102 cerr << "Unknown stemming language '" << optarg << "'.\n"
00103 "Available language names are: "
00104 << Xapian::Stem::get_available_languages() << endl;
00105 exit(1);
00106 }
00107 break;
00108 case 'b': case 'p': {
00109 const char * colon = strchr(optarg, ':');
00110 if (colon == NULL) {
00111 cerr << argv[0] << ": need ':' when setting prefix" << endl;
00112 exit(1);
00113 }
00114 string prefix(optarg, colon - optarg);
00115 string termprefix(colon + 1);
00116 if (c == 'b') {
00117 parser.add_boolean_prefix(prefix, termprefix);
00118 } else {
00119 parser.add_prefix(prefix, termprefix);
00120 }
00121 break;
00122 }
00123 case 'v':
00124 cout << PROG_NAME" - "PACKAGE_STRING << endl;
00125 exit(0);
00126 case 'h':
00127 cout << PROG_NAME" - "PROG_DESC"\n\n";
00128 show_usage();
00129 exit(0);
00130 case ':':
00131 case '?':
00132 show_usage();
00133 exit(1);
00134 }
00135 }
00136
00137 if (argc - optind != 1) {
00138 show_usage();
00139 exit(1);
00140 }
00141
00142 parser.set_database(db);
00143 parser.set_default_op(Xapian::Query::OP_OR);
00144 parser.set_stemmer(stemmer);
00145 parser.set_stemming_strategy(Xapian::QueryParser::STEM_SOME);
00146 parser.set_stopper(&mystopper);
00147
00148 Xapian::Query query = parser.parse_query(argv[optind],
00149 parser.FLAG_DEFAULT|
00150 parser.FLAG_SPELLING_CORRECTION);
00151 const string & correction = parser.get_corrected_query_string();
00152 if (!correction.empty())
00153 cout << "Did you mean: " << correction << "\n\n";
00154
00155 cout << "Parsed Query: " << query.get_description() << endl;
00156
00157 if (!have_database) {
00158 cout << "No database specified so not running the query." << endl;
00159 exit(0);
00160 }
00161
00162 Xapian::Enquire enquire(db);
00163 enquire.set_query(query);
00164
00165 Xapian::MSet mset = enquire.get_mset(0, msize);
00166
00167 cout << "MSet:" << endl;
00168 for (Xapian::MSetIterator i = mset.begin(); i != mset.end(); i++) {
00169 Xapian::Document doc = i.get_document();
00170 string data = doc.get_data();
00171 cout << *i << " [" << i.get_percent() << "%]\n" << data << "\n";
00172 }
00173 cout << flush;
00174 } catch (const Xapian::QueryParserError & e) {
00175 cout << "Couldn't parse query: " << e.get_msg() << endl;
00176 exit(1);
00177 } catch (const Xapian::Error & err) {
00178 cout << err.get_description() << endl;
00179 exit(1);
00180 }