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 19917 2008-11-25 23:47:56Z 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 "AISConnect.h" 00054 #include "Response.h" 00055 #include "StdinResponse.h" 00056 00057 using std::cerr; 00058 using std::endl; 00059 using std::flush; 00060 00061 using namespace libdap ; 00062 00063 const char *version = CVER " (" DVR " DAP/" DAP_PROTOCOL_VERSION ")"; 00064 00065 extern int libdap::dods_keep_temps; // defined in HTTPResponse.h 00066 00067 void usage(string name) 00068 { 00069 cerr << "Usage: " << name << endl; 00070 cerr << 00071 " [idDaxAVvks] [-B <db>][-c <expr>][-m <num>] <url> [<url> ...]" << 00072 endl; 00073 cerr << " [VvksM] <file> [<file> ...]" << endl; 00074 cerr << endl; 00075 cerr << "In the first form of the command, dereference the URL and" 00076 << endl; 00077 cerr << "perform the requested operations. This includes routing" << 00078 endl; 00079 cerr << "the returned information through the DAP processing" << endl; 00080 cerr << "library (parsing the returned objects, et c.). If none" << 00081 endl; 00082 cerr << "of a, d, or D are used with a URL, then the DAP library" << 00083 endl; 00084 cerr << "routines are NOT used and the URLs contents are dumped" << 00085 endl; 00086 cerr << "to standard output." << endl; 00087 cerr << endl; 00088 cerr << "In the second form of the command, assume the files are" << 00089 endl; 00090 cerr << "DataDDS objects (stored in files or read from pipes)" << endl; 00091 cerr << "and process them as if -D were given. In this case the" << 00092 endl; 00093 cerr << "information *must* contain valid MIME header in order" << 00094 endl; 00095 cerr << "to be processed." << endl; 00096 cerr << endl; 00097 cerr << "Options:" << endl; 00098 cerr << " i: For each URL, get the server version." << endl; 00099 cerr << " d: For each URL, get the the DDS." << endl; 00100 cerr << " a: For each URL, get the the DAS." << endl; 00101 cerr << " A: Use the AIS for DAS objects." << endl; 00102 cerr << " D: For each URL, get the the DataDDS." << endl; 00103 cerr << 00104 " x: For each URL, get the DDX object. Does not get data." 00105 << endl; 00106 cerr << " X: Build a DDX in getdap using the DDS and DAS." << endl; 00107 cerr << " B: <AIS xml dataBase>. Overrides .dodsrc." << endl; 00108 cerr << " v: Verbose." << endl; 00109 cerr << " V: Version." << endl; 00110 cerr << " c: <expr> is a constraint expression. Used with -D." << 00111 endl; 00112 cerr << " NB: You can use a `?' for the CE also." << endl; 00113 cerr << " k: Keep temporary files created by libdap core" << endl; 00114 cerr << " m: Request the same URL <num> times." << endl; 00115 cerr << " z: Ask the server to compress data." << endl; 00116 cerr << " s: Print Sequences using numbered rows." << endl; 00117 cerr << " M: Assume data read from a file has no MIME headers" << endl; 00118 cerr << " (the default is to assume the headers are present)." << endl; 00119 } 00120 00121 bool read_data(FILE * fp) 00122 { 00123 if (!fp) { 00124 fprintf(stderr, "getdap: Whoa!!! Null stream pointer.\n"); 00125 return false; 00126 } 00127 // Changed from a loop that used getc() to one that uses fread(). getc() 00128 // worked fine for transfers of text information, but *not* for binary 00129 // transfers. fread() will handle both. 00130 char c; 00131 while (fp && !feof(fp) && fread(&c, 1, 1, fp)) 00132 printf("%c", c); // stick with stdio 00133 00134 return true; 00135 } 00136 00137 static void print_data(DDS & dds, bool print_rows = false) 00138 { 00139 cout << "The data:" << endl; 00140 00141 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++) { 00142 BaseType *v = *i; 00143 if (print_rows && (*i)->type() == dods_sequence_c) 00144 dynamic_cast < Sequence * >(*i)->print_val_by_rows(cout); 00145 else 00146 v->print_val(cout); 00147 } 00148 00149 cout << endl << flush; 00150 } 00151 00152 int main(int argc, char *argv[]) 00153 { 00154 GetOpt getopt(argc, argv, "idaDxXAVvkB:c:m:zshM?Hp:"); 00155 int option_char; 00156 00157 bool get_das = false; 00158 bool get_dds = false; 00159 bool get_data = false; 00160 bool get_ddx = false; 00161 bool build_ddx = false; 00162 bool get_version = false; 00163 bool cexpr = false; 00164 bool verbose = false; 00165 bool multi = false; 00166 bool accept_deflate = false; 00167 bool print_rows = false; 00168 bool use_ais = false; 00169 bool mime_headers = true; 00170 int times = 1; 00171 int dap_client_major = 2; 00172 int dap_client_minor = 0; 00173 string expr = ""; 00174 string ais_db = ""; 00175 00176 #ifdef WIN32 00177 _setmode(_fileno(stdout), _O_BINARY); 00178 #endif 00179 00180 while ((option_char = getopt()) != EOF) 00181 switch (option_char) { 00182 case 'd': 00183 get_dds = true; 00184 break; 00185 case 'a': 00186 get_das = true; 00187 break; 00188 case 'D': 00189 get_data = true; 00190 break; 00191 case 'x': 00192 get_ddx = true; 00193 break; 00194 case 'X': 00195 build_ddx = true; 00196 break; 00197 case 'A': 00198 use_ais = true; 00199 break; 00200 case 'V': 00201 fprintf(stderr, "getdap version: %s\n", version); 00202 exit(0); 00203 case 'i': 00204 get_version = true; 00205 break; 00206 case 'v': 00207 verbose = true; 00208 break; 00209 case 'k': 00210 dods_keep_temps = 1; 00211 break; // keep_temp is in Connect.cc 00212 case 'c': 00213 cexpr = true; 00214 expr = getopt.optarg; 00215 break; 00216 case 'm': 00217 multi = true; 00218 times = atoi(getopt.optarg); 00219 break; 00220 case 'B': 00221 use_ais = true; 00222 ais_db = getopt.optarg; 00223 break; 00224 case 'z': 00225 accept_deflate = true; 00226 break; 00227 case 's': 00228 print_rows = true; 00229 break; 00230 case 'M': 00231 mime_headers = false; 00232 break; 00233 case 'p': { 00234 istringstream iss(getopt.optarg); 00235 char dot; 00236 iss >> dap_client_major; 00237 iss >> dot; 00238 iss >> dap_client_minor; 00239 break; 00240 } 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 if (use_ais) { 00259 if (!ais_db.empty()) 00260 url = new AISConnect(name, ais_db); 00261 else 00262 url = new AISConnect(name); 00263 } 00264 else { 00265 url = new Connect(name); 00266 } 00267 00268 // This overrides the value set in the .dodsrc file. 00269 if (accept_deflate) 00270 url->set_accept_deflate(accept_deflate); 00271 00272 if (dap_client_major > 2) 00273 url->set_xdap_protocol(dap_client_major, dap_client_minor); 00274 00275 if (url->is_local()) { 00276 if (verbose) { 00277 fprintf(stderr, 00278 "Assuming that the argument %s is a file that contains a DAP2 data object; decoding.\n", argv[i]); 00279 } 00280 00281 Response *r = 0; 00282 BaseTypeFactory factory; 00283 DataDDS dds(&factory); 00284 00285 try { 00286 if (strcmp(argv[i], "-") == 0) { 00287 r = new StdinResponse(stdin); 00288 00289 if (!r->get_stream()) 00290 throw Error("Could not open standard input."); 00291 00292 if (mime_headers) 00293 url->read_data(dds, r); // The default case 00294 else 00295 url->read_data_no_mime(dds, r); 00296 } 00297 else { 00298 r = new Response(fopen(argv[i], "r"), 0); 00299 00300 if (!r->get_stream()) 00301 throw Error(string("The input source: ") 00302 + string(argv[i]) 00303 + string(" could not be opened")); 00304 00305 url->read_data_no_mime(dds, r); 00306 } 00307 } 00308 catch (Error & e) { 00309 cerr << e.get_error_message() << endl; 00310 delete r; 00311 r = 0; 00312 delete url; 00313 url = 0; 00314 break; 00315 } 00316 00317 if (verbose) 00318 fprintf(stderr, "DAP version: %s, Server version: %s\n", 00319 url->get_protocol().c_str(), 00320 url->get_version().c_str()); 00321 00322 print_data(dds, print_rows); 00323 00324 } 00325 00326 else if (get_version) { 00327 fprintf(stderr, "DAP version: %s, Server version: %s\n", 00328 url->request_protocol().c_str(), 00329 url->get_version().c_str()); 00330 } 00331 00332 else if (get_das) { 00333 for (int j = 0; j < times; ++j) { 00334 DAS das; 00335 try { 00336 url->request_das(das); 00337 } 00338 catch (Error & e) { 00339 cerr << e.get_error_message() << endl; 00340 delete url; 00341 url = 0; 00342 continue; 00343 } 00344 00345 if (verbose) { 00346 fprintf(stderr, "DAP version: %s, Server version: %s\n", 00347 url->get_protocol().c_str(), 00348 url->get_version().c_str()); 00349 00350 fprintf(stderr, "DAS:\n"); 00351 } 00352 00353 das.print(stdout); 00354 } 00355 } 00356 00357 else if (get_dds) { 00358 for (int j = 0; j < times; ++j) { 00359 BaseTypeFactory factory; 00360 DDS dds(&factory); 00361 try { 00362 url->request_dds(dds, expr); 00363 } 00364 catch (Error & e) { 00365 cerr << e.get_error_message() << endl; 00366 delete url; 00367 url = 0; 00368 continue; // Goto the next URL or exit the loop. 00369 } 00370 00371 if (verbose) { 00372 fprintf(stderr, "DAP version: %s, Server version: %s\n", 00373 url->get_protocol().c_str(), 00374 url->get_version().c_str()); 00375 00376 fprintf(stderr, "DDS:\n"); 00377 } 00378 00379 dds.print(cout); 00380 } 00381 } 00382 00383 else if (get_ddx) { 00384 for (int j = 0; j < times; ++j) { 00385 BaseTypeFactory factory; 00386 DDS dds(&factory); 00387 try { 00388 url->request_ddx(dds, expr); 00389 } 00390 catch (Error & e) { 00391 cerr << e.get_error_message() << endl; 00392 continue; // Goto the next URL or exit the loop. 00393 } 00394 00395 if (verbose) { 00396 fprintf(stderr, "DAP version: %s, Server version: %s\n", 00397 url->get_protocol().c_str(), 00398 url->get_version().c_str()); 00399 00400 fprintf(stderr, "DDX:\n"); 00401 } 00402 00403 dds.print_xml(cout, false, "getdap; no blob yet"); 00404 } 00405 } 00406 00407 else if (build_ddx) { 00408 for (int j = 0; j < times; ++j) { 00409 BaseTypeFactory factory; 00410 DDS dds(&factory); 00411 try { 00412 url->request_dds(dds, expr); 00413 DAS das; 00414 url->request_das(das); 00415 dds.transfer_attributes(&das); 00416 } 00417 catch (Error & e) { 00418 cerr << e.get_error_message() << endl; 00419 continue; // Goto the next URL or exit the loop. 00420 } 00421 00422 if (verbose) { 00423 fprintf(stderr, "DAP version: %s, Server version: %s\n", 00424 url->get_protocol().c_str(), 00425 url->get_version().c_str()); 00426 00427 fprintf(stderr, "Client-built DDX:\n"); 00428 } 00429 00430 dds.print_xml(cout, false, "getdap; no blob yet"); 00431 } 00432 } 00433 00434 else if (get_data) { 00435 for (int j = 0; j < times; ++j) { 00436 BaseTypeFactory factory; 00437 DataDDS dds(&factory); 00438 try { 00439 DBG(cerr << "URL: " << url->URL(false) << endl); 00440 DBG(cerr << "CE: " << expr << endl); 00441 url->request_data(dds, expr); 00442 00443 if (verbose) 00444 fprintf(stderr, "DAP version: %s, Server version: %s\n", 00445 url->get_protocol().c_str(), 00446 url->get_version().c_str()); 00447 00448 print_data(dds, print_rows); 00449 } 00450 catch (Error & e) { 00451 cerr << e.get_error_message() << endl; 00452 delete url; 00453 url = 0; 00454 continue; 00455 } 00456 } 00457 } 00458 00459 else { 00460 // if (!get_das && !get_dds && !get_data) This code uses 00461 // HTTPConnect::fetch_url which cannot be accessed using an 00462 // instance of Connect. So some of the options supported by 00463 // other URLs won't work here (e.g., the verbose option 00464 // doesn't show the server version number). 00465 HTTPConnect http(RCReader::instance()); 00466 00467 // This overrides the value set in the .dodsrc file. 00468 if (accept_deflate) 00469 http.set_accept_deflate(accept_deflate); 00470 00471 if (dap_client_major > 2) 00472 url->set_xdap_protocol(dap_client_major, dap_client_minor); 00473 00474 string url_string = argv[i]; 00475 for (int j = 0; j < times; ++j) { 00476 try { 00477 Response *r = http.fetch_url(url_string); 00478 if (!read_data(r->get_stream())) { 00479 continue; 00480 } 00481 delete r; 00482 r = 0; 00483 } 00484 catch (Error & e) { 00485 cerr << e.get_error_message() << endl; 00486 continue; 00487 } 00488 } 00489 } 00490 00491 delete url; 00492 url = 0; 00493 } 00494 } 00495 catch (Error &e) { 00496 cerr << e.get_error_message() << endl; 00497 return 1; 00498 } 00499 catch (exception &e) { 00500 cerr << "C++ library exception: " << e.what() << endl; 00501 return 1; 00502 } 00503 00504 return 0; 00505 }