libdap++ Updated for version 3.8.2
|
00001 00002 // -*- mode: c++; c-basic-offset:4 -*- 00003 00004 // This file is part of libdap, A C++ implementation of the OPeNDAP Data 00005 // Access Protocol. 00006 00007 // Copyright (c) 2002,2003 OPeNDAP, Inc. 00008 // Author: James Gallagher <jgallagher@opendap.org> 00009 // 00010 // This library is free software; you can redistribute it and/or 00011 // modify it under the terms of the GNU Lesser General Public 00012 // License as published by the Free Software Foundation; either 00013 // version 2.1 of the License, or (at your option) any later version. 00014 // 00015 // This library is distributed in the hope that it will be useful, 00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 // Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public 00021 // License along with this library; if not, write to the Free Software 00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00023 // 00024 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112. 00025 00026 // (c) COPYRIGHT URI/MIT 1997-1999 00027 // Please read the full copyright statement in the file COPYRIGHT_URI. 00028 // 00029 // Authors: 00030 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu> 00031 00032 // This is the source to `getdap'; a simple tool to exercise the Connect 00033 // class. It can be used to get naked URLs as well as the DAP2 DAS and DDS 00034 // objects. jhrg. 00035 00036 #include "config.h" 00037 00038 static char rcsid[] not_used = 00039 { "$Id: getdap.cc 21695 2009-11-04 17:45:04Z jimg $" 00040 }; 00041 00042 #ifdef WIN32 00043 #include <io.h> 00044 #include <fcntl.h> 00045 #endif 00046 00047 #include <cstring> 00048 #include <string> 00049 #include <sstream> 00050 00051 #include "GetOpt.h" 00052 00053 #include "Sequence.h" 00054 #include "Connect.h" 00055 #include "Response.h" 00056 #include "StdinResponse.h" 00057 00058 using std::cerr; 00059 using std::endl; 00060 using std::flush; 00061 00062 using namespace libdap ; 00063 00064 const char *version = CVER " (" DVR " DAP/" DAP_PROTOCOL_VERSION ")"; 00065 00066 extern int libdap::dods_keep_temps; // defined in HTTPResponse.h 00067 extern int libdap::www_trace; 00068 00069 void usage(string name) 00070 { 00071 cerr << "Usage: " << name << endl; 00072 cerr << 00073 " [idDaxAVvks] [-B <db>][-c <expr>][-m <num>] <url> [<url> ...]" << 00074 endl; 00075 cerr << " [VvksM] <file> [<file> ...]" << endl; 00076 cerr << endl; 00077 cerr << "In the first form of the command, dereference the URL and" 00078 << endl; 00079 cerr << "perform the requested operations. This includes routing" << 00080 endl; 00081 cerr << "the returned information through the DAP processing" << endl; 00082 cerr << "library (parsing the returned objects, et c.). If none" << 00083 endl; 00084 cerr << "of a, d, or D are used with a URL, then the DAP library" << 00085 endl; 00086 cerr << "routines are NOT used and the URLs contents are dumped" << 00087 endl; 00088 cerr << "to standard output." << endl; 00089 cerr << endl; 00090 cerr << "In the second form of the command, assume the files are" << 00091 endl; 00092 cerr << "DataDDS objects (stored in files or read from pipes)" << endl; 00093 cerr << "and process them as if -D were given. In this case the" << 00094 endl; 00095 cerr << "information *must* contain valid MIME header in order" << 00096 endl; 00097 cerr << "to be processed." << endl; 00098 cerr << endl; 00099 cerr << "Options:" << endl; 00100 cerr << " i: For each URL, get the server version." << endl; 00101 cerr << " d: For each URL, get the the DDS." << endl; 00102 cerr << " a: For each URL, get the the DAS." << endl; 00103 cerr << " D: For each URL, get the the DataDDS." << endl; 00104 cerr << 00105 " x: For each URL, get the DDX object. Does not get data." 00106 << endl; 00107 cerr << " X: Request a DataDDX from the server (the DAP4 data response" << endl; 00108 cerr << " B: Build a DDX in getdap using the DDS and DAS." << endl; 00109 cerr << " v: Verbose output." << endl; 00110 cerr << " V: Version of this client; see 'i' for server version." << endl; 00111 cerr << " c: <expr> is a constraint expression. Used with -D/X." << 00112 endl; 00113 cerr << " NB: You can use a `?' for the CE also." << endl; 00114 cerr << " k: Keep temporary files created by libdap." << endl; 00115 cerr << " m: Request the same URL <num> times." << endl; 00116 cerr << " z: Ask the server to compress data." << endl; 00117 cerr << " s: Print Sequences using numbered rows." << endl; 00118 cerr << " M: Assume data read from a file has no MIME headers" << endl; 00119 cerr << " (the default is to assume the headers are present)." << endl; 00120 cerr << " p: Set DAP protocol to x.y" << endl; 00121 } 00122 00123 bool read_data(FILE * fp) 00124 { 00125 if (!fp) { 00126 fprintf(stderr, "getdap: Whoa!!! Null stream pointer.\n"); 00127 return false; 00128 } 00129 // Changed from a loop that used getc() to one that uses fread(). getc() 00130 // worked fine for transfers of text information, but *not* for binary 00131 // transfers. fread() will handle both. 00132 char c; 00133 while (fp && !feof(fp) && fread(&c, 1, 1, fp)) 00134 printf("%c", c); // stick with stdio 00135 00136 return true; 00137 } 00138 00139 static void print_data(DDS & dds, bool print_rows = false) 00140 { 00141 cout << "The data:" << endl; 00142 00143 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++) { 00144 BaseType *v = *i; 00145 if (print_rows && (*i)->type() == dods_sequence_c) 00146 dynamic_cast < Sequence * >(*i)->print_val_by_rows(cout); 00147 else 00148 v->print_val(cout); 00149 } 00150 00151 cout << endl << flush; 00152 } 00153 00154 int main(int argc, char *argv[]) 00155 { 00156 GetOpt getopt(argc, argv, "idaDxXBVvkc:m:zshM?Hp:t"); 00157 int option_char; 00158 00159 bool get_das = false; 00160 bool get_dds = false; 00161 bool get_data = false; 00162 bool get_ddx = false; 00163 bool get_data_ddx = false; 00164 bool build_ddx = false; 00165 bool get_version = false; 00166 bool cexpr = false; 00167 bool verbose = false; 00168 bool multi = false; 00169 bool accept_deflate = false; 00170 bool print_rows = false; 00171 bool mime_headers = true; 00172 int times = 1; 00173 int dap_client_major = 2; 00174 int dap_client_minor = 0; 00175 string expr = ""; 00176 00177 #ifdef WIN32 00178 _setmode(_fileno(stdout), _O_BINARY); 00179 #endif 00180 00181 while ((option_char = getopt()) != EOF) 00182 switch (option_char) { 00183 case 'd': 00184 get_dds = true; 00185 break; 00186 case 'a': 00187 get_das = true; 00188 break; 00189 case 'D': 00190 get_data = true; 00191 break; 00192 case 'x': 00193 get_ddx = true; 00194 break; 00195 case 'X': 00196 get_data_ddx = true; 00197 break; 00198 case 'V': 00199 fprintf(stderr, "getdap version: %s\n", version); 00200 exit(0); 00201 case 'i': 00202 get_version = true; 00203 break; 00204 case 'v': 00205 verbose = true; 00206 break; 00207 case 'k': 00208 dods_keep_temps = 1; 00209 break; // keep_temp is in Connect.cc 00210 case 'c': 00211 cexpr = true; 00212 expr = getopt.optarg; 00213 break; 00214 case 'm': 00215 multi = true; 00216 times = atoi(getopt.optarg); 00217 break; 00218 case 'B': 00219 build_ddx = true; 00220 break; 00221 case 'z': 00222 accept_deflate = true; 00223 break; 00224 case 's': 00225 print_rows = true; 00226 break; 00227 case 'M': 00228 mime_headers = false; 00229 break; 00230 case 'p': { 00231 istringstream iss(getopt.optarg); 00232 char dot; 00233 iss >> dap_client_major; 00234 iss >> dot; 00235 iss >> dap_client_minor; 00236 break; 00237 } 00238 case 't': 00239 www_trace = 1; 00240 break; 00241 case 'h': 00242 case '?': 00243 default: 00244 usage(argv[0]); 00245 exit(1); 00246 break; 00247 } 00248 00249 try { 00250 // If after processing all the command line options there is nothing 00251 // left (no URL or file) assume that we should read from stdin. 00252 for (int i = getopt.optind; i < argc; ++i) { 00253 if (verbose) 00254 fprintf(stderr, "Fetching: %s\n", argv[i]); 00255 00256 string name = argv[i]; 00257 Connect *url = 0; 00258 00259 url = new Connect(name); 00260 00261 // This overrides the value set in the .dodsrc file. 00262 if (accept_deflate) 00263 url->set_accept_deflate(accept_deflate); 00264 00265 if (dap_client_major > 2) 00266 url->set_xdap_protocol(dap_client_major, dap_client_minor); 00267 00268 if (url->is_local()) { 00269 if (verbose) { 00270 fprintf(stderr, 00271 "Assuming that the argument %s is a file that contains a DAP2 data object; decoding.\n", argv[i]); 00272 } 00273 00274 Response *r = 0; 00275 BaseTypeFactory factory; 00276 DataDDS dds(&factory); 00277 00278 try { 00279 if (strcmp(argv[i], "-") == 0) { 00280 r = new StdinResponse(stdin); 00281 00282 if (!r->get_stream()) 00283 throw Error("Could not open standard input."); 00284 00285 if (mime_headers) 00286 url->read_data(dds, r); // The default case 00287 else 00288 url->read_data_no_mime(dds, r); 00289 } 00290 else { 00291 r = new Response(fopen(argv[i], "r"), 0); 00292 00293 if (!r->get_stream()) 00294 throw Error(string("The input source: ") 00295 + string(argv[i]) 00296 + string(" could not be opened")); 00297 00298 url->read_data_no_mime(dds, r); 00299 } 00300 } 00301 catch (Error & e) { 00302 cerr << e.get_error_message() << endl; 00303 delete r; 00304 r = 0; 00305 delete url; 00306 url = 0; 00307 break; 00308 } 00309 00310 if (verbose) 00311 fprintf(stderr, "DAP version: %s, Server version: %s\n", 00312 url->get_protocol().c_str(), 00313 url->get_version().c_str()); 00314 00315 print_data(dds, print_rows); 00316 00317 } 00318 00319 else if (get_version) { 00320 fprintf(stderr, "DAP version: %s, Server version: %s\n", 00321 url->request_protocol().c_str(), 00322 url->get_version().c_str()); 00323 } 00324 00325 else if (get_das) { 00326 for (int j = 0; j < times; ++j) { 00327 DAS das; 00328 try { 00329 url->request_das(das); 00330 } 00331 catch (Error & e) { 00332 cerr << e.get_error_message() << endl; 00333 delete url; 00334 url = 0; 00335 continue; 00336 } 00337 00338 if (verbose) { 00339 fprintf(stderr, "DAP version: %s, Server version: %s\n", 00340 url->get_protocol().c_str(), 00341 url->get_version().c_str()); 00342 00343 fprintf(stderr, "DAS:\n"); 00344 } 00345 00346 das.print(stdout); 00347 } 00348 } 00349 00350 else if (get_dds) { 00351 for (int j = 0; j < times; ++j) { 00352 BaseTypeFactory factory; 00353 DDS dds(&factory); 00354 try { 00355 url->request_dds(dds, expr); 00356 } 00357 catch (Error & e) { 00358 cerr << e.get_error_message() << endl; 00359 delete url; 00360 url = 0; 00361 continue; // Goto the next URL or exit the loop. 00362 } 00363 00364 if (verbose) { 00365 fprintf(stderr, "DAP version: %s, Server version: %s\n", 00366 url->get_protocol().c_str(), 00367 url->get_version().c_str()); 00368 00369 fprintf(stderr, "DDS:\n"); 00370 } 00371 00372 dds.print(cout); 00373 } 00374 } 00375 00376 else if (get_ddx) { 00377 for (int j = 0; j < times; ++j) { 00378 BaseTypeFactory factory; 00379 DDS dds(&factory); 00380 try { 00381 url->request_ddx(dds, expr); 00382 } 00383 catch (Error & e) { 00384 cerr << e.get_error_message() << endl; 00385 continue; // Goto the next URL or exit the loop. 00386 } 00387 00388 if (verbose) { 00389 fprintf(stderr, "DAP version: %s, Server version: %s\n", 00390 url->get_protocol().c_str(), 00391 url->get_version().c_str()); 00392 00393 fprintf(stderr, "DDX:\n"); 00394 } 00395 00396 dds.print_xml(cout, false); 00397 } 00398 } 00399 00400 else if (build_ddx) { 00401 for (int j = 0; j < times; ++j) { 00402 BaseTypeFactory factory; 00403 DDS dds(&factory); 00404 try { 00405 url->request_dds(dds, expr); 00406 DAS das; 00407 url->request_das(das); 00408 dds.transfer_attributes(&das); 00409 } 00410 catch (Error & e) { 00411 cerr << e.get_error_message() << endl; 00412 continue; // Goto the next URL or exit the loop. 00413 } 00414 00415 if (verbose) { 00416 fprintf(stderr, "DAP version: %s, Server version: %s\n", 00417 url->get_protocol().c_str(), 00418 url->get_version().c_str()); 00419 00420 fprintf(stderr, "Client-built DDX:\n"); 00421 } 00422 00423 dds.print_xml(cout, false); 00424 } 00425 } 00426 00427 else if (get_data) { 00428 for (int j = 0; j < times; ++j) { 00429 BaseTypeFactory factory; 00430 DataDDS dds(&factory); 00431 try { 00432 DBG(cerr << "URL: " << url->URL(false) << endl); 00433 DBG(cerr << "CE: " << expr << endl); 00434 url->request_data(dds, expr); 00435 00436 if (verbose) 00437 fprintf(stderr, "DAP version: %s, Server version: %s\n", 00438 url->get_protocol().c_str(), 00439 url->get_version().c_str()); 00440 00441 print_data(dds, print_rows); 00442 } 00443 catch (Error & e) { 00444 cerr << e.get_error_message() << endl; 00445 delete url; 00446 url = 0; 00447 continue; 00448 } 00449 } 00450 } 00451 00452 else if (get_data_ddx) { 00453 for (int j = 0; j < times; ++j) { 00454 BaseTypeFactory factory; 00455 DataDDS dds(&factory); 00456 try { 00457 DBG(cerr << "URL: " << url->URL(false) << endl); 00458 DBG(cerr << "CE: " << expr << endl); 00459 url->request_data_ddx(dds, expr); 00460 00461 if (verbose) 00462 fprintf(stderr, "DAP version: %s, Server version: %s\n", 00463 url->get_protocol().c_str(), 00464 url->get_version().c_str()); 00465 00466 print_data(dds, print_rows); 00467 } 00468 catch (Error & e) { 00469 cerr << e.get_error_message() << endl; 00470 delete url; 00471 url = 0; 00472 continue; 00473 } 00474 } 00475 } 00476 00477 else { 00478 // if (!get_das && !get_dds && !get_data) This code uses 00479 // HTTPConnect::fetch_url which cannot be accessed using an 00480 // instance of Connect. So some of the options supported by 00481 // other URLs won't work here (e.g., the verbose option 00482 // doesn't show the server version number). 00483 HTTPConnect http(RCReader::instance()); 00484 00485 // This overrides the value set in the .dodsrc file. 00486 if (accept_deflate) 00487 http.set_accept_deflate(accept_deflate); 00488 00489 if (dap_client_major > 2) 00490 url->set_xdap_protocol(dap_client_major, dap_client_minor); 00491 00492 string url_string = argv[i]; 00493 for (int j = 0; j < times; ++j) { 00494 try { 00495 Response *r = http.fetch_url(url_string); 00496 if (!read_data(r->get_stream())) { 00497 continue; 00498 } 00499 delete r; 00500 r = 0; 00501 } 00502 catch (Error & e) { 00503 cerr << e.get_error_message() << endl; 00504 continue; 00505 } 00506 } 00507 } 00508 00509 delete url; 00510 url = 0; 00511 } 00512 } 00513 catch (Error &e) { 00514 cerr << e.get_error_message() << endl; 00515 return 1; 00516 } 00517 catch (exception &e) { 00518 cerr << "C++ library exception: " << e.what() << endl; 00519 return 1; 00520 } 00521 00522 return 0; 00523 }