libdap  Updated for version 3.17.0
getdap.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 "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 }