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