libdap  Updated for version 3.18.2
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 
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 << " [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 
105 bool 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 
121 static 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 
136 int 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 }
virtual void request_ddx(DDS &dds, string expr="")
Get the DDX from a server.
Definition: Connect.cc:702
void print(FILE *out)
Print the entire DDS to the specified file.
Definition: DDS.cc:1029
virtual string URL(bool CE=true)
Get the object&#39;s URL.
Definition: Connect.cc:1124
void set_xdap_protocol(int major, int minor)
Definition: Connect.cc:1176
Vars_iter var_begin()
Return an iterator to the first variable.
Definition: DDS.cc:805
virtual void transfer_attributes(DAS *das)
Definition: DDS.cc:287
void print_xml(FILE *out, bool constrained, const string &blob="")
Definition: DDS.cc:1130
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:330
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
virtual void print_val(FILE *out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: BaseType.cc:1011
virtual void request_dds(DDS &dds, string expr="")
Get the DDS from a server.
Definition: Connect.cc:559
void set_accept_deflate(bool deflate)
Definition: Connect.cc:1165
virtual void request_data(DataDDS &data, string expr="")
Get the DAS from a server.
Definition: Connect.cc:842
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:1059
string get_error_message() const
Definition: Error.cc:276
virtual void request_das(DAS &das)
Get the DAS from a server.
Definition: Connect.cc:427
Vars_iter var_end()
Return an iterator.
Definition: DDS.cc:817
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:395
Hold attribute data for a DAP2 dataset.
Definition: DAS.h:121
A class for error processing.
Definition: Error.h:90
Holds a DAP2 DDS.
Definition: DataDDS.h:77
string get_version()
Definition: Connect.h:185