source: gs2-extensions/parallel-building/trunk/src/src/gdbmcli-src/gdbmcli.cpp

Last change on this file was 24659, checked in by jmt12, 13 years ago

Several small changes to CLI such as new commands

  • Property svn:executable set to *
File size: 9.5 KB
Line 
1/**********************************************************************
2 *
3 * gdbmcli.cpp --
4 *
5 * Similar to txt2db (GDBM) executable in that you open a pipe to it and
6 * write commands to be applied to a GDBM database. However, unlike txt2db,
7 * this executable allows bidirectional streams (so you need to open the
8 * pipe for both reading and writing). It then supports commands of this
9 * form:
10 *
11 * \[<key>\][+\-\?]
12 * (<value>)?
13 * -{70}
14 *
15 * where: + is for add or update
16 * - is for delete
17 * ? is for lookup
18 *
19 * The aim of this executable is to allow a single, persistent, connection
20 * to a GDBM database, accessed through some kind of queued daemon, so as
21 * to support multiple readers and writers and thus parallel collection
22 * building.
23 *
24 * A component of the Greenstone digital library software
25 * from the New Zealand Digital Library Project at the
26 * University of Waikato, New Zealand.
27 *
28 * Copyright (C) 2011-2020 The New Zealand Digital Library Project
29 *
30 * This program is free software; you can redistribute it and/or modify
31 * it under the terms of the GNU General Public License as published by
32 * the Free Software Foundation; either version 2 of the License, or
33 * (at your option) any later version.
34 *
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
39 *
40 * You should have received a copy of the GNU General Public License
41 * along with this program; if not, write to the Free Software
42 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
43 *
44 **********************************************************************/
45
46
47#ifdef __WIN32__
48#include "autoconf.h"
49#include "systems.h"
50#include "gdbmconst.h"
51
52extern "C" {
53#include "gdbm.h"
54}
55
56#else
57#include <gdbm.h>
58#endif
59
60#include "gsdlconf.h"
61#include "text_t.h"
62#include <stdlib.h>
63#include <cstring>
64
65#if defined(GSDL_USE_OBJECTSPACE)
66# include <ospace\std\iostream>
67#elif defined(GSDL_USE_IOS_H)
68# include <iostream.h>
69#else
70# include <iostream>
71#endif
72
73
74void
75printUsage ()
76{
77 cerr << "===== GDBM Command Line Interface v1.0 =====" << endl << endl;
78 cerr << "usage: gdbmcli <db path>" << endl << endl;
79 cerr << "Once the program is running, the first thing it expects is the" << endl;
80 cerr << "path to the GDBM database to open, after which you can use the" << endl;
81 cerr << "commands below:" << endl;
82 cerr << " [key]+<newline>value <= adds the pair key:value" << endl;
83 cerr << " [key]<newline>value <= also adds the pair" << endl;
84 cerr << " [key]- <= deleted the pair identified by key" << endl;
85 cerr << " [key]? <= lookup the value for key" << endl;
86 cerr << " [*] <= retrieve a list of keys" << endl;
87 cerr << " [] <= exit " << endl << endl;
88}
89
90int
91main (int argc, char *argv[])
92{
93 if (argc != 2)
94 {
95 printUsage();
96 exit(0);
97 }
98
99 char *dbname = argv[1];
100
101 // open the database
102 // note that GDBM_FAST is obsolete on newer versions of gdbm
103 int read_write = GDBM_WRCREAT | GDBM_FAST;
104 int block_size = 0;
105#ifdef __WIN32__
106 GDBM_FILE dbf = gdbm_open(dbname, block_size, read_write, 00664, NULL, 1);
107#else
108 GDBM_FILE dbf = gdbm_open(dbname, block_size, read_write, 00664, NULL);
109#endif
110 if (dbf == NULL)
111 {
112 cerr << "couldn't create " << dbname << endl;
113 exit(0);
114 }
115
116 // Start reading commands from STDIN
117 bool quit = false;
118 char c;
119 cin.get(c);
120 while (!cin.eof() && !quit)
121 {
122 text_t key = "";
123 bool action_delete = false;
124 bool action_lookup = false;
125 bool action_keys = false;
126 text_t value = "";
127 int num_dashes = 0;
128
129 // Parse out 'key' from [key]\n
130 // scan for first occurrence of [
131 while (!cin.eof() && c != '[')
132 {
133 cin.get(c);
134 }
135 if (!cin.eof())
136 {
137 cin.get(c); // skip [
138 }
139
140 // now look for closing ], building up 'key' as we go
141 while (!cin.eof() && c != ']')
142 {
143 key.push_back ((unsigned char)c);
144 cin.get(c);
145 }
146
147 // Empty key means exit
148 if (key.empty())
149 {
150 quit = true;
151 }
152 else
153 {
154 // * as a key means return a list of keys
155 if (key == "*")
156 {
157 action_keys = true;
158 }
159
160 if (key == "?")
161 {
162 cout << "0.1" << endl;
163 gdbm_close (dbf);
164 return 0;
165 }
166
167 // retrieve the command token
168 if (!cin.eof())
169 {
170 cin.get(c);
171 if (c == '+')
172 {
173 // defaults to action_add anyway
174 cin.get(c);
175 }
176 else if (c == '?')
177 {
178 action_lookup = true;
179 cin.get(c);
180 }
181 else if (c == '-')
182 {
183 action_delete = true;
184 cin.get(c);
185 }
186 }
187
188 // Returning the list of all keys (one per line) is of highest priority
189 if (action_keys)
190 {
191 datum key_data = gdbm_firstkey (dbf);
192 bool first_key = true;
193 while (key_data.dptr != NULL)
194 {
195 if (first_key)
196 {
197 first_key = false;
198 }
199 else
200 {
201 cout << endl;
202 }
203 for (int i = 0; i < key_data.dsize; ++i)
204 {
205 cout << key_data.dptr[i];
206 }
207 /* get next key */
208 datum nextkey_data = gdbm_nextkey (dbf, key_data);
209 /* free old key's dptr, otherwise causes memory leak */
210 free(key_data.dptr);
211 /* can now safely copy content of nextkey into key */
212 key_data = nextkey_data;
213 }
214 }
215 // if we've been asked for a lookup, retrieve the information for this
216 // key, write to STDOUT, and then continue processing STDIN for further
217 // commands
218 else if (action_lookup)
219 {
220 // convert key to a datum datatype
221 datum key_data;
222 key_data.dptr = key.getcstr();
223 if (key_data.dptr == NULL)
224 {
225 cerr << "NULL key_data.dptr" << endl;
226 exit (0);
227 }
228 key_data.dsize = strlen(key_data.dptr);
229
230 datum value_data;
231 value_data = gdbm_fetch (dbf, key_data);
232 for (int i = 0; i < value_data.dsize; ++i)
233 {
234 cout << value_data.dptr[i];
235 }
236 free(value_data.dptr);
237 free(key_data.dptr);
238 }
239 // if we've been asked to delete a key/value pair, do so and then
240 // continue processing STDIN for further commands
241 else if (action_delete)
242 {
243 // convert key to a datum datatype
244 datum key_data;
245 key_data.dptr = key.getcstr();
246 if (key_data.dptr == NULL)
247 {
248 cerr << "NULL key_data.dptr" << endl;
249 exit (0);
250 }
251 key_data.dsize = strlen(key_data.dptr);
252 // delete the given key
253 if (gdbm_delete(dbf, key_data) < 0)
254 {
255 cerr << "gdbm_delete returned an error trying to delete key " << key << ": " << gdbm_strerror (gdbm_errno) <<endl;
256 }
257 free(key_data.dptr);
258 }
259 // Everything else is an add/update. Read in value, action and then
260 // continue processing STDIN for further commands
261 else
262 {
263 // convert key to a datum datatype
264 datum key_data;
265 key_data.dptr = key.getcstr();
266 if (key_data.dptr == NULL)
267 {
268 cerr << "NULL key_data.dptr" << endl;
269 exit (0);
270 }
271 key_data.dsize = strlen(key_data.dptr);
272
273 // eat up whitespace
274 while (!cin.eof() && (c == '\t' || c == ' ' || c == '\n' || c == '\r'))
275 {
276 cin.get(c);
277 }
278 // parse in value (if any), watching for the 70 dashes that mark the end
279 text_t tmp = "";
280 while (!cin.eof() && (num_dashes < 70))
281 {
282 // - reset number of dashes on newline
283 if (c == '\n')
284 {
285 tmp.push_back ((unsigned char)c);
286 num_dashes = 0;
287 }
288 // Here we are able to process both Windows-specific text files
289 // (containing carriage-return, newline) and Linux text files
290 // (containing only newline characters) by ignoring the Windows'
291 // carriage-return altogether so that we produce a uniform database
292 // file from either system's type of text file.
293 // If we don't ignore the carriage return here, txt.gz files
294 // produced on Windows cause a GS library running on Linux to break.
295 // - reset number of dashes on carriage return
296 else if (c == '\r')
297 {
298 num_dashes = 0;
299 }
300 else if (c == '-')
301 {
302 tmp.push_back ((unsigned char)c);
303 ++num_dashes;
304 }
305 else
306 {
307 value += tmp;
308 value.push_back ((unsigned char)c);
309 tmp = "";
310 num_dashes = 0;
311 }
312 cin.get(c);
313 }
314
315 // convert value to a datum datatype
316 datum value_data;
317 value_data.dptr = value.getcstr();
318 if (value_data.dptr == NULL)
319 {
320 cerr << "NULL value_data.dptr" << endl;
321 exit (0);
322 }
323 value_data.dsize = strlen(value_data.dptr);
324 // store the value
325 if (gdbm_store (dbf, key_data, value_data, GDBM_REPLACE) < 0)
326 {
327 cerr << "gdbm_store returned an error" << endl;
328 exit (0);
329 }
330 // done with value
331 free(value_data.dptr);
332 free(key_data.dptr);
333 }
334 // - always output 70 hyphens when finished
335 cout << endl << "----------------------------------------------------------------------" << endl;
336 // done with key too
337 }
338 }
339 gdbm_close (dbf);
340 cout << "Database updated. Goodbye." << endl;
341 return 0;
342}
Note: See TracBrowser for help on using the repository browser.