libdap Updated for version 3.18.1
getdap.cc
1
2// -*- mode: c++; c-basic-offset:4 -*-
3
4// This file is part of libdap, A C++ implementation of the OPeNDAP Data
5// Access Protocol.
6
7// Copyright (c) 2002,2003 OPeNDAP, Inc.
8// Author: James Gallagher <jgallagher@opendap.org>
9//
10// This library is free software; you can redistribute it and/or
11// modify it under the terms of the GNU Lesser General Public
12// License as published by the Free Software Foundation; either
13// version 2.1 of the License, or (at your option) any later version.
14//
15// This library is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18// Lesser General Public License for more details.
19//
20// You should have received a copy of the GNU Lesser General Public
21// License along with this library; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23//
24// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25
26// (c) COPYRIGHT URI/MIT 1997-1999
27// Please read the full copyright statement in the file COPYRIGHT_URI.
28//
29// Authors:
30// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
31
32// This is the source to `getdap'; a simple tool to exercise the Connect
33// class. It can be used to get naked URLs as well as the DAP2 DAS and DDS
34// objects. jhrg.
35
36#include "config.h"
37
38#ifdef WIN32
39#include <io.h>
40#include <fcntl.h>
41#endif
42
43#include <cstring>
44#include <string>
45#include <sstream>
46
47#include "GetOpt.h"
48
49#include "Sequence.h"
50#include "Connect.h"
51#include "Response.h"
52#include "StdinResponse.h"
53
54using std::cerr;
55using std::endl;
56using std::flush;
57
58using namespace libdap ;
59
60const char *version = CVER " (" DVR " DAP/" DAP_PROTOCOL_VERSION ")";
61
62extern int libdap::dods_keep_temps; // defined in HTTPResponse.h
63extern int libdap::www_trace;
64
65void usage(string name)
66{
67 cerr << "Usage: " << name << endl;
68 cerr << " [idaDxBzp vVkms][-c <expr>][-m <num>] <url> [<url> ...]" << endl;
69 cerr << " [M vVkms] <file> [<file> ...]" << endl;
70 cerr << endl;
71 cerr << "In the first form of the command, dereference the URL and" << endl;
72 cerr << "perform the requested operations. This includes routing" << endl;
73 cerr << "the returned information through the DAP processing" << endl;
74 cerr << "library (parsing the returned objects, et c.). If none" << endl;
75 cerr << "of a, d, or D are used with a URL, then the DAP library" << endl;
76 cerr << "routines are NOT used and the URLs contents are dumped" << endl;
77 cerr << "to standard output." << endl;
78 cerr << endl;
79 cerr << "In the second form of the command, assume the files are" << endl;
80 cerr << "DataDDS objects (stored in files or read from pipes)" << endl;
81 cerr << "and process them as if -D were given. In this case the" << endl;
82 cerr << "information *must* contain valid MIME header in order" << endl;
83 cerr << "to be processed." << endl;
84 cerr << endl;
85 cerr << "Options:" << endl;
86 cerr << " i: For each URL, get the server version." << endl;
87 cerr << " d: For each URL, get the the DDS." << endl;
88 cerr << " a: For each URL, get the the DAS." << endl;
89 cerr << " D: For each URL, get the the DataDDS." << endl;
90 cerr << " x: For each URL, get the (DAP2) DDX object. Does not get data." << endl;
91 cerr << " B: Build a DDX in getdap using the DDS and DAS." << endl;
92 cerr << " v: Verbose output." << endl;
93 cerr << " V: Version of this client; see 'i' for server version." << endl;
94 cerr << " c: <expr> is a constraint expression. Used with -D/X and -d/r" << endl;
95 cerr << " NB: You can use a `?' for the CE also." << endl;
96 cerr << " k: Keep temporary files created by libdap." << endl;
97 cerr << " m: Request the same URL <num> times." << endl;
98 cerr << " z: Ask the server to compress data." << endl;
99 cerr << " s: Print Sequences using numbered rows." << endl;
100 cerr << " M: Assume data read from a file has no MIME headers" << endl;
101 cerr << " (the default is to assume the headers are present)." << endl;
102 cerr << " p: Set DAP protocol to x.y" << endl;
103}
104
105bool read_data(FILE * fp)
106{
107 if (!fp) {
108 fprintf(stderr, "getdap: Whoa!!! Null stream pointer.\n");
109 return false;
110 }
111 // Changed from a loop that used getc() to one that uses fread(). getc()
112 // worked fine for transfers of text information, but *not* for binary
113 // transfers. fread() will handle both.
114 char c;
115 while (fp && !feof(fp) && fread(&c, 1, 1, fp))
116 printf("%c", c); // stick with stdio
117
118 return true;
119}
120
121static void print_data(DDS & dds, bool print_rows = false)
122{
123 cout << "The data:" << endl;
124
125 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++) {
126 BaseType *v = *i;
127 if (print_rows && (*i)->type() == dods_sequence_c)
128 dynamic_cast < Sequence * >(*i)->print_val_by_rows(cout);
129 else
130 v->print_val(cout);
131 }
132
133 cout << endl << flush;
134}
135
136int main(int argc, char *argv[])
137{
138 GetOpt getopt(argc, argv, "idaDxrXBVvkc:m:zshM?Hp:t");
139 int option_char;
140
141 bool get_das = false;
142 bool get_dds = false;
143 bool get_data = false;
144 bool get_ddx = false;
145 bool build_ddx = false;
146 bool get_version = false;
147 bool cexpr = false;
148 bool verbose = false;
149 bool multi = false;
150 bool accept_deflate = false;
151 bool print_rows = false;
152 bool mime_headers = true;
153 int times = 1;
154 int dap_client_major = 2;
155 int dap_client_minor = 0;
156 string expr = "";
157
158#ifdef WIN32
159 _setmode(_fileno(stdout), _O_BINARY);
160#endif
161
162 while ((option_char = getopt()) != -1)
163 switch (option_char) {
164 case 'd':
165 get_dds = true;
166 break;
167 case 'a':
168 get_das = true;
169 break;
170 case 'D':
171 get_data = true;
172 break;
173 case 'x':
174 get_ddx = true;
175 break;
176 case 'V':
177 fprintf(stderr, "getdap version: %s\n", version);
178 exit(0);
179 case 'i':
180 get_version = true;
181 break;
182 case 'v':
183 verbose = true;
184 break;
185 case 'k':
186 dods_keep_temps = 1;
187 break; // keep_temp is in Connect.cc
188 case 'c':
189 cexpr = true;
190 expr = getopt.optarg;
191 break;
192 case 'm':
193 multi = true;
194 times = atoi(getopt.optarg);
195 break;
196 case 'B':
197 build_ddx = true;
198 break;
199 case 'z':
200 accept_deflate = true;
201 break;
202 case 's':
203 print_rows = true;
204 break;
205 case 'M':
206 mime_headers = false;
207 break;
208 case 'p': {
209 istringstream iss(getopt.optarg);
210 char dot;
211 iss >> dap_client_major;
212 iss >> dot;
213 iss >> dap_client_minor;
214 break;
215 }
216 case 't':
217 www_trace = 1;
218 break;
219 case 'h':
220 case '?':
221 default:
222 usage(argv[0]);
223 exit(1);
224 break;
225 }
226
227 try {
228 // If after processing all the command line options there is nothing
229 // left (no URL or file) assume that we should read from stdin.
230 for (int i = getopt.optind; i < argc; ++i) {
231 if (verbose)
232 fprintf(stderr, "Fetching: %s\n", argv[i]);
233
234 string name = argv[i];
235 Connect *url = 0;
236
237 url = new Connect(name);
238
239 // This overrides the value set in the .dodsrc file.
240 if (accept_deflate)
241 url->set_accept_deflate(accept_deflate);
242
243 if (dap_client_major > 2)
244 url->set_xdap_protocol(dap_client_major, dap_client_minor);
245
246 if (url->is_local()) {
247 if (verbose) {
248 fprintf(stderr, "Assuming that the argument %s is a file that contains a response object; decoding.\n", argv[i]);
249 }
250
251 Response *r = 0;
252
253 BaseTypeFactory factory;
254 DataDDS dds(&factory);
255
256 try {
257 if (strcmp(argv[i], "-") == 0) {
258 r = new StdinResponse(stdin);
259
260 if (!r->get_stream())
261 throw Error("Could not open standard input.");
262
263 if (mime_headers)
264 url->read_data(dds, r); // The default case
265 else
266 url->read_data_no_mime(dds, r);
267 }
268 else {
269 r = new Response(fopen(argv[i], "r"), 0);
270
271 if (!r->get_stream())
272 throw Error(string("The input source: ")
273 + string(argv[i])
274 + string(" could not be opened"));
275
276 url->read_data_no_mime(dds, r);
277 }
278 }
279 catch (Error & e) {
280 cerr << e.get_error_message() << endl;
281 delete r;
282 r = 0;
283 delete url;
284 url = 0;
285 break;
286 }
287
288 if (verbose)
289 fprintf(stderr, "DAP version: %s, Server version: %s\n",
290 url->get_protocol().c_str(),
291 url->get_version().c_str());
292
293 print_data(dds, print_rows);
294
295 }
296
297 else if (get_version) {
298 fprintf(stderr, "DAP version: %s, Server version: %s\n",
299 url->request_protocol().c_str(),
300 url->get_version().c_str());
301 }
302
303 else if (get_das) {
304 for (int j = 0; j < times; ++j) {
305 DAS das;
306 try {
307 url->request_das(das);
308 }
309 catch (Error & e) {
310 cerr << e.get_error_message() << endl;
311 delete url;
312 url = 0;
313 continue;
314 }
315
316 if (verbose) {
317 fprintf(stderr, "DAP version: %s, Server version: %s\n",
318 url->get_protocol().c_str(),
319 url->get_version().c_str());
320
321 fprintf(stderr, "DAS:\n");
322 }
323
324 das.print(stdout);
325 }
326 }
327
328 else if (get_dds) {
329 for (int j = 0; j < times; ++j) {
330 BaseTypeFactory factory;
331 DDS dds(&factory);
332 try {
333 url->request_dds(dds, expr);
334 }
335 catch (Error & e) {
336 cerr << e.get_error_message() << endl;
337 delete url;
338 url = 0;
339 continue; // Goto the next URL or exit the loop.
340 }
341
342 if (verbose) {
343 fprintf(stderr, "DAP version: %s, Server version: %s\n",
344 url->get_protocol().c_str(),
345 url->get_version().c_str());
346
347 fprintf(stderr, "DDS:\n");
348 }
349
350 dds.print(cout);
351 }
352 }
353
354 else if (get_ddx) {
355 for (int j = 0; j < times; ++j) {
356 BaseTypeFactory factory;
357 DDS dds(&factory);
358 try {
359 url->request_ddx(dds, expr);
360 }
361 catch (Error & e) {
362 cerr << e.get_error_message() << endl;
363 continue; // Goto the next URL or exit the loop.
364 }
365
366 if (verbose) {
367 fprintf(stderr, "DAP version: %s, Server version: %s\n",
368 url->get_protocol().c_str(),
369 url->get_version().c_str());
370
371 fprintf(stderr, "DDX:\n");
372 }
373
374 dds.print_xml(cout, false);
375 }
376 }
377
378 else if (build_ddx) {
379 for (int j = 0; j < times; ++j) {
380 BaseTypeFactory factory;
381 DDS dds(&factory);
382 try {
383 url->request_dds(dds, expr);
384 DAS das;
385 url->request_das(das);
386 dds.transfer_attributes(&das);
387 }
388 catch (Error & e) {
389 cerr << e.get_error_message() << endl;
390 continue; // Goto the next URL or exit the loop.
391 }
392
393 if (verbose) {
394 fprintf(stderr, "DAP version: %s, Server version: %s\n",
395 url->get_protocol().c_str(),
396 url->get_version().c_str());
397
398 fprintf(stderr, "Client-built DDX:\n");
399 }
400
401 dds.print_xml(cout, false);
402 }
403 }
404
405 else if (get_data) {
406 for (int j = 0; j < times; ++j) {
407 BaseTypeFactory factory;
408 DataDDS dds(&factory);
409 try {
410 DBG(cerr << "URL: " << url->URL(false) << endl);
411 DBG(cerr << "CE: " << expr << endl);
412 url->request_data(dds, expr);
413
414 if (verbose)
415 fprintf(stderr, "DAP version: %s, Server version: %s\n",
416 url->get_protocol().c_str(),
417 url->get_version().c_str());
418
419 print_data(dds, print_rows);
420 }
421 catch (Error & e) {
422 cerr << e.get_error_message() << endl;
423 delete url;
424 url = 0;
425 continue;
426 }
427 }
428 }
429 else {
430 // if (!get_das && !get_dds && !get_data ...) This code uses
431 // HTTPConnect::fetch_url which cannot be accessed using an
432 // instance of Connect. So some of the options supported by
433 // other URLs won't work here (e.g., the verbose option
434 // doesn't show the server version number).
435 HTTPConnect http(RCReader::instance());
436
437 // This overrides the value set in the .dodsrc file.
438 if (accept_deflate)
439 http.set_accept_deflate(accept_deflate);
440
441 if (dap_client_major > 2)
442 url->set_xdap_protocol(dap_client_major, dap_client_minor);
443
444 string url_string = argv[i];
445 for (int j = 0; j < times; ++j) {
446 try {
447 Response *r = http.fetch_url(url_string);
448 if (!read_data(r->get_stream())) {
449 continue;
450 }
451 delete r;
452 r = 0;
453 }
454 catch (Error & e) {
455 cerr << e.get_error_message() << endl;
456 continue;
457 }
458 }
459 }
460
461 delete url;
462 url = 0;
463 }
464 }
465 catch (Error &e) {
466 cerr << e.get_error_message() << endl;
467 return 1;
468 }
469 catch (exception &e) {
470 cerr << "C++ library exception: " << e.what() << endl;
471 return 1;
472 }
473
474 return 0;
475}
Definition: GetOpt.h:39
The basic data type for the DODS DAP types.
Definition: BaseType.h:118
virtual void print_val(FILE *out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: BaseType.cc:1011
Holds information about the link from a DAP2 client to a dataset.
Definition: Connect.h:130
void set_accept_deflate(bool deflate)
Definition: Connect.cc:1165
string get_version()
Definition: Connect.h:185
string get_protocol()
Definition: Connect.h:193
virtual void request_ddx(DDS &dds, string expr="")
Get the DDX from a server.
Definition: Connect.cc:702
virtual void read_data_no_mime(DataDDS &data, Response *rs)
Read data from a file which does not have response MIME headers. This method is a companion to read_d...
Definition: Connect.cc:1059
void set_xdap_protocol(int major, int minor)
Definition: Connect.cc:1176
virtual string URL(bool CE=true)
Get the object's URL.
Definition: Connect.cc:1124
virtual void request_data(DataDDS &data, string expr="")
Get the DAS from a server.
Definition: Connect.cc:842
virtual void request_das(DAS &das)
Get the DAS from a server.
Definition: Connect.cc:427
virtual string request_protocol()
Definition: Connect.cc:395
virtual void request_dds(DDS &dds, string expr="")
Get the DDS from a server.
Definition: Connect.cc:559
virtual void read_data(DataDDS &data, Response *rs)
Read data which is preceded by MIME headers. This method works for both data dds and data ddx respons...
Definition: Connect.cc:986
Hold attribute data for a DAP2 dataset.
Definition: DAS.h:122
virtual void print(FILE *out, bool dereference=false)
Definition: DAS.cc:330
virtual void transfer_attributes(DAS *das)
Definition: DDS.cc:287
void print(FILE *out)
Print the entire DDS to the specified file.
Definition: DDS.cc:1029
void print_xml(FILE *out, bool constrained, const string &blob="")
Definition: DDS.cc:1130
Vars_iter var_begin()
Return an iterator to the first variable.
Definition: DDS.cc:805
Vars_iter var_end()
Return an iterator.
Definition: DDS.cc:817
Holds a DAP2 DDS.
Definition: DataDDS.h:78
A class for error processing.
Definition: Error.h:91
string get_error_message() const
Definition: Error.cc:276
Holds a sequence.
Definition: Sequence.h:163
Encapsulate a response read from stdin.
Definition: StdinResponse.h:45