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