libdap  Updated for version 3.17.0
getdap4.cc
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 "DMR.h"
00050 #include "XMLWriter.h"
00051 #include "D4BaseTypeFactory.h"
00052 #include "D4Group.h"
00053 #include "D4Sequence.h"
00054 #include "D4Connect.h"
00055 #include "StdinResponse.h"
00056 #include "HTTPConnect.h"
00057 #include "RCReader.h"
00058 
00059 using namespace std;
00060 using namespace libdap ;
00061 
00062 const char *version = CVER " (" DVR " DAP/" DAP_PROTOCOL_VERSION ")";
00063 #if 0
00064 extern int libdap::dods_keep_temps;     // defined in HTTPResponse.h
00065 extern int libdap::www_trace;
00066 #endif
00067 static void usage(const string &name)
00068 {
00069         cerr << "Usage: " << name << endl;
00070         cerr << " [dD vVikmzstM][-c <expr>][-m <num>] <url> [<url> ...] | <file> [<file> ...]" << endl;
00071         cerr << endl;
00072         cerr << "In the first form of the command, dereference the URL and" << endl;
00073         cerr << "perform the requested operations. This includes routing" << endl;
00074         cerr << "the returned information through the DAP processing" << endl;
00075         cerr << "library (parsing the returned objects, et c.). If none" << endl;
00076         cerr << "of a, d, or D are used with a URL, then the DAP library" << endl;
00077         cerr << "routines are NOT used and the URLs contents are dumped" << endl;
00078         cerr << "to standard output." << endl;
00079         cerr << endl;
00080         cerr << "In the second form of the command, assume the files are" << endl;
00081         cerr << "DataDDS objects (stored in files or read from pipes)" << endl;
00082         cerr << "and process them as if -D were given. In this case the" << endl;
00083         cerr << "information *must* contain valid MIME header in order" << endl;
00084         cerr << "to be processed." << endl;
00085         cerr << endl;
00086         cerr << "Options:" << endl;
00087         cerr << "        d: For each URL, get the (DAP4) DMR object. Does not get data." << endl;
00088         cerr << "        D: For each URL, get the DAP4 Data response." << endl;
00089         cerr << endl;
00090         cerr << "        v: Verbose output." << endl;
00091         cerr << "        V: Version of this client; see 'i' for server version." << endl;
00092         cerr << "        i: For each URL, get the server version." << endl;
00093         cerr << "        k: Keep temporary files created by libdap." << endl;
00094         cerr << "        m: Request the same URL <num> times." << endl;
00095         cerr << "        z: Ask the server to compress data." << endl;
00096         cerr << "        s: Print Sequences using numbered rows." << endl;
00097         cerr << "        t: Trace www accesses." << endl;
00098         cerr << "        M: Assume data read from a file has no MIME headers; use only with files" << endl;
00099         cerr << endl;
00100         cerr << "        c: <expr> is a constraint expression. Used with -d/D" << endl;
00101         cerr << "           NB: You can use a `?' for the CE also." << endl;
00102 }
00103 
00104 // Used for raw http access/transfer
00105 bool read_data(FILE * fp)
00106 {
00107     if (!fp) {
00108         fprintf(stderr, "getdap4: 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 read_response_from_file(D4Connect *url, DMR &dmr, Response &r, bool mime_headers, bool get_dap4_data, bool get_dmr)
00122 {
00123     if (mime_headers) {
00124         if (get_dap4_data)
00125                 url->read_data(dmr, r);
00126         else if (get_dmr)
00127                 url->read_dmr(dmr, r);
00128         else
00129                 throw Error("Only supports Data or DMR responses");
00130     }
00131     else {
00132         if (get_dap4_data)
00133                 url->read_data_no_mime(dmr, r);
00134         else if (get_dmr)
00135                 url->read_dmr_no_mime(dmr, r);
00136         else
00137                 throw Error("Only supports Data or DMR responses");
00138     }
00139 }
00140 
00141 static void print_group_data(D4Group *g, bool print_rows = false)
00142 {
00143     for (Constructor::Vars_iter i = g->var_begin(), e = g->var_end(); i != e; i++) {
00144         if (print_rows && (*i)->type() == dods_sequence_c)
00145             dynamic_cast<D4Sequence &>(**i).print_val_by_rows(cout);
00146         else
00147             (*i)->print_val(cout);
00148     }
00149 
00150     for (D4Group::groupsIter gi = g->grp_begin(), ge = g->grp_end(); gi != ge; ++gi) {
00151         print_group_data(*gi, print_rows);
00152     }
00153 }
00154 
00155 static void print_data(DMR &dmr, bool print_rows = false)
00156 {
00157     cout << "The data:" << endl;
00158 
00159     D4Group *g = dmr.root();
00160 
00161     print_group_data(g, print_rows);
00162 
00163     cout << endl << flush;
00164 }
00165 
00166 int main(int argc, char *argv[])
00167 {
00168     GetOpt getopt(argc, argv, "[dDvVikrm:Mzstc:]");
00169     int option_char;
00170 
00171     bool get_dmr = false;
00172     bool get_dap4_data = false;
00173     bool get_version = false;
00174     bool cexpr = false;
00175     bool verbose = false;
00176     bool multi = false;
00177     bool accept_deflate = false;
00178     bool print_rows = false;
00179     bool mime_headers = true;
00180     bool report_errors = false;
00181     int times = 1;
00182     int dap_client_major = 4;
00183     int dap_client_minor = 0;
00184     string expr = "";
00185 
00186 #ifdef WIN32
00187     _setmode(_fileno(stdout), _O_BINARY);
00188 #endif
00189 
00190     while ((option_char = getopt()) != -1)
00191         switch (option_char) {
00192         case 'd':
00193             get_dmr = true;
00194             break;
00195         case 'D':
00196             get_dap4_data = true;
00197             break;
00198         case 'v':
00199             verbose = true;
00200             break;
00201         case 'V':
00202                 cerr << "getdap4 version: " << version << endl;
00203             exit(0);
00204         case 'i':
00205             get_version = true;
00206             break;
00207 #if 0
00208         case 'k':
00209             dods_keep_temps = 1;
00210             break;              // keep_temp is in Connect.cc
00211 #endif
00212         case 'r':
00213                 report_errors = true;
00214                 break;
00215         case 'm':
00216             multi = true;
00217             times = atoi(getopt.optarg);
00218             break;
00219         case 'z':
00220             accept_deflate = true;
00221             break;
00222         case 's':
00223             print_rows = true;
00224             break;
00225         case 'M':
00226             mime_headers = false;
00227             break;
00228 #if 0
00229         case 't':
00230             www_trace = 1;
00231             break;
00232 #endif
00233         case 'c':
00234             cexpr = true;
00235             expr = getopt.optarg;
00236             break;
00237         case 'h':
00238         case '?':
00239         default:
00240             usage(argv[0]);
00241             exit(1);
00242             break;
00243         }
00244 
00245     try {
00246         // If after processing all the command line options there is nothing
00247         // left (no URL or file) assume that we should read from stdin.
00248         for (int i = getopt.optind; i < argc; ++i) {
00249             if (verbose)
00250                 cerr << "Fetching: " << argv[i] << endl;
00251 
00252             string name = argv[i];
00253             D4Connect *url = 0;
00254             // auto_ptr? jhrg 10/19/15
00255             url = new D4Connect(name);
00256 
00257             // This overrides the value set in the .dodsrc file.
00258             if (accept_deflate)
00259                 url->set_accept_deflate(accept_deflate);
00260 
00261             if (dap_client_major > 2)
00262                 url->set_xdap_protocol(dap_client_major, dap_client_minor);
00263 
00264             if (url->is_local()) {
00265                 if (verbose)
00266                     cerr << "Assuming " << argv[i] << " is a file that contains a response object; decoding." << endl;
00267 
00268                 try {
00269                     D4BaseTypeFactory factory;
00270                     DMR dmr(&factory);
00271 
00272                     if (strcmp(argv[i], "-") == 0) {
00273                         StdinResponse r(cin);
00274 
00275                         if (!r.get_cpp_stream())
00276                             throw Error("Could not open standard input.");
00277 
00278                         read_response_from_file(url, dmr, r, mime_headers, get_dap4_data, get_dmr);
00279                     }
00280                     else {
00281                         fstream f(argv[i], std::ios_base::in);
00282                         if (!f.is_open() || f.bad() || f.eof())
00283                                 throw Error((string)"Could not open: " + argv[i]);
00284 
00285                         Response r(&f, 0);
00286 
00287                         read_response_from_file(url, dmr, r, mime_headers, get_dap4_data, get_dmr);
00288                     }
00289 
00290                     if (verbose)
00291                         cerr << "DAP version: " << url->get_protocol().c_str() << " Server version: "
00292                                                 << url->get_version().c_str() << endl;
00293 
00294                     // Always write the DMR
00295                     XMLWriter xml;
00296                     dmr.print_dap4(xml);
00297                     cout << xml.get_doc() << endl;
00298 
00299                     if (get_dap4_data)
00300                         print_data(dmr, print_rows);
00301                 }
00302                 catch (Error & e) {
00303                     cerr << "Error: " << e.get_error_message() << endl;
00304                     delete url; url = 0;
00305                     if (report_errors)
00306                         return EXIT_FAILURE;
00307                 }
00308             }
00309             else if (get_dmr) {
00310                 for (int j = 0; j < times; ++j) {
00311                     D4BaseTypeFactory factory;
00312                     DMR dmr(&factory);
00313                     try {
00314                         url->request_dmr(dmr, expr);
00315 
00316                         if (verbose) {
00317                             cout << "DAP version: " << url->get_protocol() << ", Server version: " << url->get_version() << endl;
00318                             cout << "DMR:" << endl;
00319                         }
00320 
00321                         XMLWriter xml;
00322                         dmr.print_dap4(xml);
00323                         cout << xml.get_doc() << endl;
00324                     }
00325                     catch (Error & e) {
00326                         cerr << e.get_error_message() << endl;
00327                         if (report_errors)
00328                                 return EXIT_FAILURE;
00329                         continue;       // Goto the next URL or exit the loop.
00330                     }
00331                 }
00332             }
00333             else if (get_dap4_data) {
00334                  for (int j = 0; j < times; ++j) {
00335                      D4BaseTypeFactory factory;
00336                      DMR dmr(&factory);
00337                      try {
00338                          url->request_dap4_data(dmr, expr);
00339 
00340                          if (verbose) {
00341                              cout << "DAP version: " << url->get_protocol() << ", Server version: " << url->get_version() << endl;
00342                              cout << "DMR:" << endl;
00343                          }
00344 
00345                          XMLWriter xml;
00346                          dmr.print_dap4(xml);
00347                          cout << xml.get_doc() << endl;
00348 
00349                          print_data(dmr, print_rows);
00350                     }
00351                      catch (Error & e) {
00352                          cerr << e.get_error_message() << endl;
00353                          if (report_errors)
00354                              return EXIT_FAILURE;
00355                          continue;       // Goto the next URL or exit the loop.
00356                      }
00357                  }
00358             }
00359             else {
00360                 HTTPConnect http(RCReader::instance());
00361 
00362                 // This overrides the value set in the .dodsrc file.
00363                 if (accept_deflate)
00364                     http.set_accept_deflate(accept_deflate);
00365 
00366                 if (dap_client_major > 2)
00367                     url->set_xdap_protocol(dap_client_major, dap_client_minor);
00368 
00369                 string url_string = argv[i];
00370                 for (int j = 0; j < times; ++j) {
00371                     try {
00372                         HTTPResponse *r = http.fetch_url(url_string);
00373                         if (verbose) {
00374                                 vector<string> *headers = r->get_headers();
00375                                 copy(headers->begin(), headers->end(), ostream_iterator<string>(cout, "\n"));
00376                         }
00377                         if (!read_data(r->get_stream())) {
00378                             continue;
00379                         }
00380                         delete r;
00381                         r = 0;
00382                     }
00383                     catch (Error & e) {
00384                         cerr << e.get_error_message() << endl;
00385                         if (report_errors)
00386                             return EXIT_FAILURE;
00387                         continue;
00388                     }
00389                 }
00390             }
00391 
00392 #if 0
00393             else if (get_version) {
00394                 fprintf(stderr, "DAP version: %s, Server version: %s\n",
00395                         url->request_protocol().c_str(),
00396                         url->get_version().c_str());
00397             }
00398 #endif
00399 
00400             delete url;  url = 0;
00401         }
00402     }
00403     catch (Error &e) {
00404         cerr << "Error: " << e.get_error_message() << endl;
00405         cerr << "exiting" << endl;
00406         return 1;
00407     }
00408     catch (exception &e) {
00409         cerr << "C++ library exception: " << e.what() << endl;
00410         cerr << "exiting" << endl;
00411         return 1;
00412     }
00413 
00414     return 0;
00415 }