date.c: Add hard-coded definition of HAVE_TIMEZONE
[notmuch] / xapian-dump.cc
1 /* xapian-dump: Create a textual dump of a Xapian database.
2  *
3  * Copyright © 2009 Carl Worth
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see http://www.gnu.org/licenses/ .
17  *
18  * Author: Carl Worth <cworth@cworth.org>
19  */
20
21 /* Currently the dumped data includes:
22  *
23  *      All document IDs
24  *
25  * And for each document ID:
26  *
27  *      Document data
28  *      All document terms
29  *      All document values
30  */
31
32 #include <cstdlib>
33 #include <iostream>
34 #include <algorithm>
35
36 #include <xapian.h>
37
38 using namespace std;
39
40 vector<int> UNSERIALIZE;
41
42 unsigned int MAX_TERMS = 0;
43
44 static void
45 print_escaped_string (const char *s)
46 {
47     printf ("\"");
48
49     while (*s) {
50         if (*s == '"')
51             printf ("\\");
52         printf ("%c", *s);
53         s++;
54     }
55
56     printf ("\"");
57 }
58
59 static void
60 print_document_terms (Xapian::Document doc)
61 {
62     Xapian::TermIterator it;
63     unsigned int i;
64
65     printf ("    {\n");
66
67     for (it = doc.termlist_begin (), i = 0;
68          it != doc.termlist_end ();
69          it++, i++)
70     {
71         printf ("        ");
72         print_escaped_string ((*it).c_str());
73         printf (",\n");
74     }
75
76     for ( ; i < MAX_TERMS; i++)
77         printf ("        \"\",\n");
78
79     printf ("    },\n");
80 }
81
82 static int
83 vector_int_contains (vector<int> v, int i)
84 {
85     vector<int>::iterator result;
86
87     result = find (v.begin(), v.end(), i);
88
89     return result != v.end();
90 }
91
92 static void
93 print_document_values (Xapian::Document doc)
94 {
95     Xapian::ValueIterator i;
96     int value_no, value_int;
97     double value_float;
98
99     for (i = doc.values_begin (); i != doc.values_end (); i++) {
100         value_no = i.get_valueno();
101
102         printf ("    ");
103
104         if (vector_int_contains (UNSERIALIZE, value_no)) {
105             value_float = Xapian::sortable_unserialise (*i);
106             value_int = value_float;
107             if (value_int == value_float)
108                 printf ("%d", value_int);
109             else
110                 printf ("\"%f\"", value_float);
111         } else {
112             print_escaped_string ((*i).c_str ());
113         }
114
115         printf (",\n");
116     }
117
118 }
119
120 static void
121 print_document (Xapian::Database db, Xapian::docid id)
122 {
123     Xapian::Document doc;
124
125     printf ("{\n");
126
127     doc = db.get_document (id);
128
129     printf ("    \"%s\",\n", doc.get_data ().c_str());
130
131     print_document_terms (doc);
132
133     print_document_values (doc);
134
135     printf ("},\n");
136 }
137
138 int
139 main (int argc, char *argv[])
140 {
141     const char *database_path;
142     int i;
143
144     if (argc < 2) {
145         fprintf (stderr, "Usage: %s <path-to-xapian-database> [value_nos...]\n",
146                  argv[0]);
147         fprintf (stderr, "Dumps data from the given database.\n");
148         fprintf (stderr, "The values corresponding to any value numbers given on the command line\n");
149         fprintf (stderr, "will be unserialized to an before being printed.\n");
150         exit (1);
151     }
152
153     database_path = argv[1];
154
155     UNSERIALIZE = vector<int> ();
156
157     for (i = 2; i < argc; i++)
158         UNSERIALIZE.push_back (atoi (argv[i]));
159
160     try {
161         Xapian::Database db;
162         Xapian::PostingIterator i;
163         Xapian::docid doc_id;
164
165         db = Xapian::Database (database_path);
166
167         for (i = db.postlist_begin (""); i != db.postlist_end (""); i++) {
168             Xapian::Document doc;
169
170             doc_id = *i;
171
172             doc = db.get_document (doc_id);
173
174             if (doc.termlist_count () > MAX_TERMS)
175                 MAX_TERMS = doc.termlist_count ();
176         }
177
178         printf ("#define MAX_TERMS %d\n\n", MAX_TERMS);
179
180         printf ("typedef struct {\n"
181                 "    char data[255];\n"
182                 "    char terms[MAX_TERMS][255];\n"
183                 "    char message_id[255];\n"
184                 "    char thread_id[4096];\n"
185                 "    time_t time;\n"
186                 "} document_dump_t;\n\n");
187
188         printf ("document_dump_t dump[] = {\n");
189
190         for (i = db.postlist_begin (""); i != db.postlist_end (""); i++) {
191             doc_id = *i;
192
193             print_document (db, doc_id);
194         }
195
196         printf ("};\n");
197
198     } catch (const Xapian::Error &error) {
199         cerr << "A Xapian exception occurred: " << error.get_msg () << endl;
200         exit (1);
201     }
202
203     return 0;
204 }