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