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