bin/xapian-inspect.cc

Go to the documentation of this file.
00001 
00004 /* Copyright (C) 2007,2008 Olly Betts
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00019  */
00020 
00021 #include <config.h>
00022 
00023 #include <iomanip>
00024 #include <iostream>
00025 #include <string>
00026 #include <stdio.h>
00027 
00028 #include "flint_table.h"
00029 #include "flint_cursor.h"
00030 #include "stringutils.h"
00031 #include "utils.h"
00032 
00033 #include <xapian.h>
00034 
00035 #include "gnu_getopt.h"
00036 
00037 using namespace std;
00038 
00039 #define PROG_NAME "xapian-inspect"
00040 #define PROG_DESC "Inspect the contents of a flint table for development or debugging"
00041 
00042 #define OPT_HELP 1
00043 #define OPT_VERSION 2
00044 
00045 static void show_usage() {
00046     cout << "Usage: "PROG_NAME" [OPTIONS] TABLE\n\n"
00047 "Options:\n"
00048 "  --help           display this help and exit\n"
00049 "  --version        output version information and exit" << endl;
00050 }
00051 
00052 static void
00053 display_nicely(const string & data) {
00054     string::const_iterator i;
00055     for (i = data.begin(); i != data.end(); ++i) {
00056         unsigned char ch = *i;
00057         if (ch < 32 || ch >= 127) {
00058             switch (ch) {
00059                 case '\n': cout << "\\n"; break;
00060                 case '\r': cout << "\\r"; break;
00061                 case '\t': cout << "\\t"; break;
00062                 default: {
00063                     char buf[20];
00064                     sprintf(buf, "\\x%02x", (int)ch);
00065                     cout << buf;
00066                 }
00067             }
00068         } else if (ch == '\\') {
00069             cout << "\\\\";
00070         } else {
00071             cout << ch;
00072         }
00073     }
00074 }
00075 
00076 static void
00077 show_help()
00078 {
00079     cout << "Commands:\n"
00080             "next   : Next entry (alias 'n' or '')\n"
00081             "prev   : Previous entry (alias 'p')\n"
00082             "goto X : Goto entry X (alias 'g')\n"
00083             "help   : Show this (alias 'h' or '?')\n"
00084             "quit   : Quit this utility (alias 'q')" << endl;
00085 }
00086 
00087 int
00088 main(int argc, char **argv)
00089 {
00090     const struct option long_opts[] = {
00091         {"help",        no_argument, 0, OPT_HELP},
00092         {"version",     no_argument, 0, OPT_VERSION},
00093         {NULL,          0, 0, 0}
00094     };
00095 
00096     int c;
00097     while ((c = gnu_getopt_long(argc, argv, "", long_opts, 0)) != -1) {
00098         switch (c) {
00099             case OPT_HELP:
00100                 cout << PROG_NAME" - "PROG_DESC"\n\n";
00101                 show_usage();
00102                 exit(0);
00103             case OPT_VERSION:
00104                 cout << PROG_NAME" - "PACKAGE_STRING << endl;
00105                 exit(0);
00106             default:
00107                 show_usage();
00108                 exit(1);
00109         }
00110     }
00111 
00112     if (argc - optind != 1) {
00113         show_usage();
00114         exit(1);
00115     }
00116 
00117     // Path to the table to inspect.
00118     string table_name(argv[optind]);
00119     bool arg_is_directory = dir_exists(table_name);
00120     if (endswith(table_name, ".DB"))
00121         table_name.resize(table_name.size() - 2);
00122     if (!endswith(table_name, '.'))
00123         table_name += '.';
00124     if (arg_is_directory && !file_exists(table_name + "DB")) {
00125         cerr << argv[0] << ": You need to specify a single Btree table, not a database directory." << endl;
00126         exit(1);
00127     }
00128 
00129     try {
00130         FlintTable table(table_name, true);
00131         table.open();
00132         if (table.get_entry_count() == 0) {
00133             cout << "No entries!" << endl;
00134             exit(0);
00135         }
00136 
00137         FlintCursor cursor(&table);
00138         cursor.find_entry(string());
00139         cursor.next();
00140 
00141         show_help();
00142         cout << endl;
00143 
00144         while (!cin.eof()) {
00145             cout << "Key: ";
00146             display_nicely(cursor.current_key);
00147             cout << "\nTag: ";
00148             cursor.read_tag();
00149             display_nicely(cursor.current_tag);
00150             cout << "\n";
00151 wait_for_input:
00152             cout << "? " << flush;
00153 
00154             string input;
00155             getline(cin, input);
00156             if (cin.eof()) break;
00157 
00158             if (endswith(input, '\r'))
00159                 input.resize(input.size() - 1);
00160 
00161             if (input.empty() || input == "n" || input == "next") {
00162                 if (cursor.after_end() || !cursor.next()) {
00163                     cout << "At end already." << endl;
00164                     goto wait_for_input;
00165                 }
00166                 continue;
00167             } else if (input == "p" || input == "prev") {
00168                 // If the cursor has fallen off the end, point it back at
00169                 // the last entry.
00170                 if (cursor.after_end()) cursor.find_entry(cursor.current_key);
00171                 if (!cursor.prev()) {
00172                     cout << "At start already." << endl;
00173                     goto wait_for_input;
00174                 }
00175                 continue;
00176             } else if (startswith(input, "g ")) {
00177                 if (!cursor.find_entry(input.substr(2))) {
00178                     cout << "No exact match, going to entry before." << endl;
00179                 }
00180                 continue;
00181             } else if (startswith(input, "goto ")) {
00182                 if (!cursor.find_entry(input.substr(5))) {
00183                     cout << "No exact match, going to entry before." << endl;
00184                 }
00185                 continue;
00186             } else if (input == "q" || input == "quit") {
00187                 break;
00188             } else if (input == "h" || input == "help" || input == "?") {
00189                 show_help();
00190                 goto wait_for_input;
00191             } else {
00192                 cout << "Unknown command." << endl;
00193                 goto wait_for_input;
00194             }
00195         }
00196     } catch (const Xapian::Error &error) {
00197         cerr << argv[0] << ": " << error.get_description() << endl;
00198         exit(1);
00199     }
00200 }

Documentation for Xapian (version 1.0.10).
Generated on 24 Dec 2008 by Doxygen 1.5.2.