00001
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
00169
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 }