libdap++ Updated for version 3.8.2

getdap.cc

Go to the documentation of this file.
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 }