libdap Updated for version 3.21.1
libdap4 is an implementation of OPeNDAP's DAP protocol.
getdap.cc
Go to the documentation of this file.
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 <fcntl.h>
40#include <io.h>
41#endif
42
43#include <cstring>
44#include <sstream>
45#include <string>
46
47#include <cstdio> //SBL 12.3.19
48
49#include "GetOpt.h"
50
51#include "Connect.h"
52#include "HTTPResponse.h"
53#include "RCReader.h"
54#include "Response.h"
55#include "Sequence.h"
56#include "StdinResponse.h"
57#include "debug.h"
58
59using std::cerr;
60using std::endl;
61using std::flush;
62
63using namespace libdap;
64
65const char *version = CVER " (" DVR " DAP/" DAP_PROTOCOL_VERSION ")";
66
67extern int libdap::dods_keep_temps; // defined in HTTPResponse.h
68extern int libdap::www_trace;
70
71void usage(string name) {
72 cerr << "Usage: " << name << endl;
73 cerr << " [idaDxBzp vVkms][-c <expr>][-m <num>] <url> [<url> ...]" << endl;
74 cerr << " [M vVkms] <file> [<file> ...]" << endl;
75 cerr << endl;
76 cerr << "In the first form of the command, dereference the URL and" << endl;
77 cerr << "perform the requested operations. This includes routing" << endl;
78 cerr << "the returned information through the DAP processing" << endl;
79 cerr << "library (parsing the returned objects, et c.). If none" << endl;
80 cerr << "of a, d, or D are used with a URL, then the DAP library" << endl;
81 cerr << "routines are NOT used and the URLs contents are dumped" << endl;
82 cerr << "to standard output." << endl;
83 cerr << endl;
84 cerr << "In the second form of the command, assume the files are" << endl;
85 cerr << "DataDDS objects (stored in files or read from pipes)" << endl;
86 cerr << "and process them as if -D were given. In this case the" << endl;
87 cerr << "information *must* contain valid MIME header in order" << endl;
88 cerr << "to be processed." << endl;
89 cerr << endl;
90 cerr << "Options:" << endl;
91 cerr << " i: For each URL, get the server version." << endl;
92 cerr << " d: For each URL, get the the DDS." << endl;
93 cerr << " a: For each URL, get the the DAS." << endl;
94 cerr << " D: For each URL, get the the DataDDS." << endl;
95 cerr << " x: For each URL, get the (DAP2) DDX object. Does not get data." << endl;
96 cerr << " B: Build a DDX in getdap using the DDS and DAS." << endl;
97 cerr << " v: Verbose output." << endl;
98 cerr << " e: Extensive (or very) verbose." << endl;
99 cerr << " V: Version of this client; see 'i' for server version." << endl;
100 cerr << " c: <expr> is a constraint expression. Used with -D/X and -d/r" << endl;
101 cerr << " NB: You can use a `?' for the CE also." << endl;
102 cerr << " k: Keep temporary files created by libdap." << endl;
103 cerr << " m: Request the same URL <num> times." << endl;
104 cerr << " z: Ask the server to compress data." << endl;
105 cerr << " s: Print Sequences using numbered rows." << endl;
106 cerr << " M: Assume data read from a file has no MIME headers" << endl;
107 cerr << " (the default is to assume the headers are present)." << endl;
108 cerr << " p: Set DAP protocol to x.y" << endl;
109}
110
111bool read_data(FILE *fp) {
112 if (!fp) {
113 fprintf(stderr, "getdap: Whoa!!! Null stream pointer.\n");
114 return false;
115 }
116 // Changed from a loop that used getc() to one that uses fread(). getc()
117 // worked fine for transfers of text information, but *not* for binary
118 // transfers. fread() will handle both.
119 char c = 0;
120 while (fp && !feof(fp) && fread(&c, 1, 1, fp))
121 printf("%c", c); // stick with stdio
122
123 return true;
124}
125
126static void print_data(DDS &dds, bool print_rows = false) {
127 cout << "The data:" << endl;
128
129 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++) {
130 BaseType *v = *i;
131 if (print_rows && (*i)->type() == dods_sequence_c)
132 dynamic_cast<Sequence *>(*i)->print_val_by_rows(cout);
133 else
134 v->print_val(cout);
135 }
136
137 cout << endl << flush;
138}
139
140int main(int argc, char *argv[]) {
141 GetOpt getopt(argc, argv, "idaDxrXBVvekc:m:zshM?Hp:t");
142 int option_char;
143
144 bool get_das = false;
145 bool get_dds = false;
146 bool get_data = false;
147 bool get_ddx = false;
148 bool build_ddx = false;
149 bool get_version = false;
150 bool verbose = false;
151 bool accept_deflate = false;
152 bool print_rows = false;
153 bool mime_headers = true;
154 int times = 1;
155 int dap_client_major = 2;
156 int dap_client_minor = 0;
157 string expr;
158
159#ifdef WIN32
160 _setmode(_fileno(stdout), _O_BINARY);
161#endif
162
163 while ((option_char = getopt()) != -1)
164 switch (option_char) {
165 case 'd':
166 get_dds = true;
167 break;
168 case 'a':
169 get_das = true;
170 break;
171 case 'D':
172 get_data = true;
173 break;
174 case 'x':
175 get_ddx = true;
176 break;
177 case 'V':
178 fprintf(stderr, "getdap version: %s\n", version);
179 exit(0);
180 case 'i':
181 get_version = true;
182 break;
183 case 'v':
184 verbose = true;
185 www_trace = 1;
186 break;
187 case 'e':
188 verbose = true;
189 www_trace = 1;
191 break;
192 case 'k':
193 dods_keep_temps = 1;
194 break; // keep_temp is in Connect.cc
195 case 'c':
196 expr = getopt.optarg;
197 break;
198 case 'm':
199 times = atoi(getopt.optarg);
200 break;
201 case 'B':
202 build_ddx = true;
203 break;
204 case 'z':
205 accept_deflate = true;
206 break;
207 case 's':
208 print_rows = true;
209 break;
210 case 'M':
211 mime_headers = false;
212 break;
213 case 'p': {
214 istringstream iss(getopt.optarg);
215 char dot;
216 iss >> dap_client_major;
217 iss >> dot;
218 iss >> dap_client_minor;
219 break;
220 }
221 case 't':
222 www_trace = 1;
223 break;
224 case 'h':
225 case '?':
226 default:
227 usage(argv[0]);
228 exit(1);
229 }
230
231 try {
232 // If after processing all the command line options there is nothing
233 // left (no URL or file) assume that we should read from stdin.
234 for (int i = getopt.optind; i < argc; ++i) {
235 if (verbose)
236 fprintf(stderr, "Fetching: %s\n", argv[i]);
237
238 string name = argv[i];
239 Connect *url = 0;
240
241 url = new Connect(name);
242
243 // This overrides the value set in the .dodsrc file.
244 if (accept_deflate)
245 url->set_accept_deflate(accept_deflate);
246
247 if (dap_client_major > 2)
248 url->set_xdap_protocol(dap_client_major, dap_client_minor);
249
250 if (url->is_local()) {
251 if (verbose) {
252 fprintf(stderr,
253 "Assuming that the argument %s is a file that contains a response object; decoding.\n",
254 argv[i]);
255 }
256
257 Response *r = 0;
258
259 BaseTypeFactory factory;
260 DataDDS dds(&factory);
261
262 try {
263 if (strcmp(argv[i], "-") == 0) {
264 r = new StdinResponse(stdin);
265
266 if (!r->get_stream())
267 throw Error("Could not open standard input.");
268
269 if (mime_headers)
270 url->read_data(dds, r); // The default case
271 else
272 url->read_data_no_mime(dds, r);
273 } else {
274 r = new Response(fopen(argv[i], "r"), 0);
275
276 if (!r->get_stream())
277 throw Error(string("The input source: ") + string(argv[i]) +
278 string(" could not be opened"));
279
280 url->read_data_no_mime(dds, r);
281 }
282 } catch (Error &e) {
283 cerr << e.get_error_message() << endl;
284 delete r;
285 r = 0;
286 delete url;
287 url = 0;
288 break;
289 }
290
291 if (verbose)
292 fprintf(stderr, "DAP version: %s, Server version: %s\n", url->get_protocol().c_str(),
293 url->get_version().c_str());
294
295 print_data(dds, print_rows);
296
297 }
298
299 else if (get_version) {
300 fprintf(stderr, "DAP version: %s, Server version: %s\n", url->request_protocol().c_str(),
301 url->get_version().c_str());
302 }
303
304 else if (get_das) {
305 for (int j = 0; j < times; ++j) {
306 DAS das;
307 try {
308 url->request_das(das);
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", url->get_protocol().c_str(),
318 url->get_version().c_str());
319
320 fprintf(stderr, "DAS:\n");
321 }
322
323 das.print(stdout);
324 }
325 }
326
327 else if (get_dds) {
328 for (int j = 0; j < times; ++j) {
329 BaseTypeFactory factory;
330 DDS dds(&factory);
331 try {
332 url->request_dds(dds, expr);
333 } catch (Error &e) {
334 cerr << e.get_error_message() << endl;
335 delete url;
336 url = 0;
337 continue; // Goto the next URL or exit the loop.
338 }
339
340 if (verbose) {
341 fprintf(stderr, "DAP version: %s, Server version: %s\n", url->get_protocol().c_str(),
342 url->get_version().c_str());
343
344 fprintf(stderr, "DDS:\n");
345 }
346
347 dds.print(cout);
348 }
349 }
350
351 else if (get_ddx) {
352 for (int j = 0; j < times; ++j) {
353 BaseTypeFactory factory;
354 DDS dds(&factory);
355 try {
356 url->request_ddx(dds, expr);
357 } catch (Error &e) {
358 cerr << e.get_error_message() << endl;
359 continue; // Goto the next URL or exit the loop.
360 }
361
362 if (verbose) {
363 fprintf(stderr, "DAP version: %s, Server version: %s\n", url->get_protocol().c_str(),
364 url->get_version().c_str());
365
366 fprintf(stderr, "DDX:\n");
367 }
368
369 dds.print_xml(cout, false);
370 }
371 }
372
373 else if (build_ddx) {
374 for (int j = 0; j < times; ++j) {
375 BaseTypeFactory factory;
376 DDS dds(&factory);
377 try {
378 url->request_dds(dds, expr);
379 DAS das;
380 url->request_das(das);
381 dds.transfer_attributes(&das);
382 } catch (Error &e) {
383 cerr << e.get_error_message() << endl;
384 continue; // Goto the next URL or exit the loop.
385 }
386
387 if (verbose) {
388 fprintf(stderr, "DAP version: %s, Server version: %s\n", url->get_protocol().c_str(),
389 url->get_version().c_str());
390
391 fprintf(stderr, "Client-built DDX:\n");
392 }
393
394 dds.print_xml(cout, false);
395 }
396 }
397
398 else if (get_data) {
399 for (int j = 0; j < times; ++j) {
400 BaseTypeFactory factory;
401 DataDDS dds(&factory);
402 try {
403 DBG(cerr << "URL: " << url->URL(false) << endl);
404 DBG(cerr << "CE: " << expr << endl);
405 url->request_data(dds, expr);
406
407 if (verbose)
408 fprintf(stderr, "DAP version: %s, Server version: %s\n", url->get_protocol().c_str(),
409 url->get_version().c_str());
410
411 print_data(dds, print_rows);
412 } catch (Error &e) {
413 cerr << e.get_error_message() << endl;
414 delete url;
415 url = 0;
416 continue;
417 }
418 }
419 } else {
420 // if (!get_das && !get_dds && !get_data ...) This code uses
421 // HTTPConnect::fetch_url which cannot be accessed using an
422 // instance of Connect. So some of the options supported by
423 // other URLs won't work here (e.g., the verbose option
424 // doesn't show the server version number).
426
427 // This overrides the value set in the .dodsrc file.
428 if (accept_deflate)
429 http.set_accept_deflate(accept_deflate);
430
431 if (dap_client_major > 2)
432 url->set_xdap_protocol(dap_client_major, dap_client_minor);
433
434 string url_string = argv[i];
435 for (int j = 0; j < times; ++j) {
436 try {
437 Response *r = http.fetch_url(url_string);
438 if (!read_data(r->get_stream())) {
439 continue;
440 }
441 delete r;
442 r = 0;
443 } catch (Error &e) {
444 cerr << e.get_error_message() << endl;
445 continue;
446 }
447 }
448 }
449
450 delete url;
451 url = 0;
452 }
453 } catch (Error &e) {
454 cerr << e.get_error_message() << endl;
455 // return 1;
456 return EXIT_FAILURE;
457 } catch (exception &e) {
458 cerr << "C++ library exception: " << e.what() << endl;
459 // return 1;
460 return EXIT_FAILURE;
461 }
462
463 // return 0;
464 return EXIT_SUCCESS;
465}
char * optarg
Definition GetOpt.h:95
int optind
Definition GetOpt.h:108
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:949
Holds information about the link from a DAP2 client to a dataset.
Definition Connect.h:127
void set_accept_deflate(bool deflate)
Definition Connect.cc:1113
string get_version()
Definition Connect.h:182
string get_protocol()
Definition Connect.h:187
virtual void request_ddx(DDS &dds, string expr="")
Get the DDX from a server.
Definition Connect.cc:681
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:1016
void set_xdap_protocol(int major, int minor)
Definition Connect.cc:1123
virtual string URL(bool CE=true)
Get the object's URL.
Definition Connect.cc:1075
virtual void request_data(DataDDS &data, string expr="")
Get the DAS from a server.
Definition Connect.cc:814
virtual void request_das(DAS &das)
Get the DAS from a server.
Definition Connect.cc:419
virtual string request_protocol()
Definition Connect.cc:389
virtual void request_dds(DDS &dds, string expr="")
Get the DDS from a server.
Definition Connect.cc:545
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:948
Hold attribute data for a DAP2 dataset.
Definition DAS.h:119
virtual void print(FILE *out, bool dereference=false)
Definition DAS.cc:304
virtual void transfer_attributes(DAS *das)
Definition DDS.cc:231
void print(FILE *out)
Print the entire DDS to the specified file.
Definition DDS.cc:812
void print_xml(FILE *out, bool constrained, const string &blob="")
Definition DDS.cc:1113
Vars_iter var_begin()
Definition DDS.h:336
Vars_iter var_end()
Return an iterator.
Definition DDS.h:341
std::vector< BaseType * >::iterator Vars_iter
Definition DDS.h:211
Holds a DAP2 DDS.
Definition DataDDS.h:76
A class for error processing.
Definition Error.h:92
const char * what() const noexcept override
The pointer is valid only for the lifetime of the Error instance. jhrg 9/22/20.
Definition Error.h:152
std::string get_error_message() const
Definition Error.cc:212
void set_accept_deflate(bool deflate)
HTTPResponse * fetch_url(const std::string &url)
static RCReader * instance()
Definition RCReader.cc:427
virtual FILE * get_stream() const
Definition Response.h:103
Holds a sequence.
Definition Sequence.h:162
virtual void print_val_by_rows(ostream &out, string space="", bool print_decl_p=true, bool print_row_numbers=true)
Definition Sequence.cc:1090
Encapsulate a response read from stdin.
#define CVER
Definition config.h:32
#define DAP_PROTOCOL_VERSION
Definition config.h:41
#define DVR
Definition config.h:80
#define DBG(x)
Definition debug.h:58
int main(int argc, char *argv[])
Definition getdap.cc:140
const char * version
Definition getdap.cc:65
bool read_data(FILE *fp)
Definition getdap.cc:111
top level DAP object to house generic methods
Definition AISConnect.cc:30
@ dods_sequence_c
Definition Type.h:108
const string usage
Definition DODSFilter.cc:89
int www_trace
int dods_keep_temps
int www_trace_extensive