libdap  Updated for version 3.20.4
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 "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 = 0;
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  }
225 
226  try {
227  // If after processing all the command line options there is nothing
228  // left (no URL or file) assume that we should read from stdin.
229  for (int i = getopt.optind; i < argc; ++i) {
230  if (verbose)
231  fprintf(stderr, "Fetching: %s\n", argv[i]);
232 
233  string name = argv[i];
234  Connect *url = 0;
235 
236  url = new Connect(name);
237 
238  // This overrides the value set in the .dodsrc file.
239  if (accept_deflate)
240  url->set_accept_deflate(accept_deflate);
241 
242  if (dap_client_major > 2)
243  url->set_xdap_protocol(dap_client_major, dap_client_minor);
244 
245  if (url->is_local()) {
246  if (verbose) {
247  fprintf(stderr, "Assuming that the argument %s is a file that contains a response object; decoding.\n", argv[i]);
248  }
249 
250  Response *r = 0;
251 
252  BaseTypeFactory factory;
253  DataDDS dds(&factory);
254 
255  try {
256  if (strcmp(argv[i], "-") == 0) {
257  r = new StdinResponse(stdin);
258 
259  if (!r->get_stream())
260  throw Error("Could not open standard input.");
261 
262  if (mime_headers)
263  url->read_data(dds, r); // The default case
264  else
265  url->read_data_no_mime(dds, r);
266  }
267  else {
268  r = new Response(fopen(argv[i], "r"), 0);
269 
270  if (!r->get_stream())
271  throw Error(string("The input source: ")
272  + string(argv[i])
273  + string(" could not be opened"));
274 
275  url->read_data_no_mime(dds, r);
276  }
277  }
278  catch (Error & e) {
279  cerr << e.get_error_message() << endl;
280  delete r;
281  r = 0;
282  delete url;
283  url = 0;
284  break;
285  }
286 
287  if (verbose)
288  fprintf(stderr, "DAP version: %s, Server version: %s\n",
289  url->get_protocol().c_str(),
290  url->get_version().c_str());
291 
292  print_data(dds, print_rows);
293 
294  }
295 
296  else if (get_version) {
297  fprintf(stderr, "DAP version: %s, Server version: %s\n",
298  url->request_protocol().c_str(),
299  url->get_version().c_str());
300  }
301 
302  else if (get_das) {
303  for (int j = 0; j < times; ++j) {
304  DAS das;
305  try {
306  url->request_das(das);
307  }
308  catch (Error & e) {
309  cerr << e.get_error_message() << endl;
310  delete url;
311  url = 0;
312  continue;
313  }
314 
315  if (verbose) {
316  fprintf(stderr, "DAP version: %s, Server version: %s\n",
317  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  }
334  catch (Error & e) {
335  cerr << e.get_error_message() << endl;
336  delete url;
337  url = 0;
338  continue; // Goto the next URL or exit the loop.
339  }
340 
341  if (verbose) {
342  fprintf(stderr, "DAP version: %s, Server version: %s\n",
343  url->get_protocol().c_str(),
344  url->get_version().c_str());
345 
346  fprintf(stderr, "DDS:\n");
347  }
348 
349  dds.print(cout);
350  }
351  }
352 
353  else if (get_ddx) {
354  for (int j = 0; j < times; ++j) {
355  BaseTypeFactory factory;
356  DDS dds(&factory);
357  try {
358  url->request_ddx(dds, expr);
359  }
360  catch (Error & e) {
361  cerr << e.get_error_message() << endl;
362  continue; // Goto the next URL or exit the loop.
363  }
364 
365  if (verbose) {
366  fprintf(stderr, "DAP version: %s, Server version: %s\n",
367  url->get_protocol().c_str(),
368  url->get_version().c_str());
369 
370  fprintf(stderr, "DDX:\n");
371  }
372 
373  dds.print_xml(cout, false);
374  }
375  }
376 
377  else if (build_ddx) {
378  for (int j = 0; j < times; ++j) {
379  BaseTypeFactory factory;
380  DDS dds(&factory);
381  try {
382  url->request_dds(dds, expr);
383  DAS das;
384  url->request_das(das);
385  dds.transfer_attributes(&das);
386  }
387  catch (Error & e) {
388  cerr << e.get_error_message() << endl;
389  continue; // Goto the next URL or exit the loop.
390  }
391 
392  if (verbose) {
393  fprintf(stderr, "DAP version: %s, Server version: %s\n",
394  url->get_protocol().c_str(),
395  url->get_version().c_str());
396 
397  fprintf(stderr, "Client-built DDX:\n");
398  }
399 
400  dds.print_xml(cout, false);
401  }
402  }
403 
404  else if (get_data) {
405  for (int j = 0; j < times; ++j) {
406  BaseTypeFactory factory;
407  DataDDS dds(&factory);
408  try {
409  DBG(cerr << "URL: " << url->URL(false) << endl);
410  DBG(cerr << "CE: " << expr << endl);
411  url->request_data(dds, expr);
412 
413  if (verbose)
414  fprintf(stderr, "DAP version: %s, Server version: %s\n",
415  url->get_protocol().c_str(),
416  url->get_version().c_str());
417 
418  print_data(dds, print_rows);
419  }
420  catch (Error & e) {
421  cerr << e.get_error_message() << endl;
422  delete url;
423  url = 0;
424  continue;
425  }
426  }
427  }
428  else {
429  // if (!get_das && !get_dds && !get_data ...) This code uses
430  // HTTPConnect::fetch_url which cannot be accessed using an
431  // instance of Connect. So some of the options supported by
432  // other URLs won't work here (e.g., the verbose option
433  // doesn't show the server version number).
434  HTTPConnect http(RCReader::instance());
435 
436  // This overrides the value set in the .dodsrc file.
437  if (accept_deflate)
438  http.set_accept_deflate(accept_deflate);
439 
440  if (dap_client_major > 2)
441  url->set_xdap_protocol(dap_client_major, dap_client_minor);
442 
443  string url_string = argv[i];
444  for (int j = 0; j < times; ++j) {
445  try {
446  Response *r = http.fetch_url(url_string);
447  if (!read_data(r->get_stream())) {
448  continue;
449  }
450  delete r;
451  r = 0;
452  }
453  catch (Error & e) {
454  cerr << e.get_error_message() << endl;
455  continue;
456  }
457  }
458  }
459 
460  delete url;
461  url = 0;
462  }
463  }
464  catch (Error &e) {
465  cerr << e.get_error_message() << endl;
466  return 1;
467  }
468  catch (exception &e) {
469  cerr << "C++ library exception: " << e.what() << endl;
470  return 1;
471  }
472 
473  return 0;
474 }
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'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: AlarmHandler.h:35
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:275
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