]> git.mxchange.org Git - flightgear.git/blobdiff - src/Main/metar_main.cxx
Support a --no-default-config option.
[flightgear.git] / src / Main / metar_main.cxx
index 4fdc9dd9599919934627e04a7ec0639cf654f5a0..b1a39078afdb5d98df13fa9671493c7dd713ff97 100644 (file)
 //
 // You should have received a copy of the GNU General Public License
 // along with this program; if not, write to the Free Software
-// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //
 // $Id$
 
 #include <iomanip>
 #include <sstream>
+#include <iostream>
+#include <string.h>
+#include <time.h>
+#include <cstdlib>
 
 #include <simgear/debug/logstream.hxx>
-#include <simgear/structure/exception.hxx>
 #include <simgear/environment/metar.hxx>
+#include <simgear/structure/exception.hxx>
+
+#include <simgear/io/HTTPClient.hxx>
+#include <simgear/io/HTTPRequest.hxx>
+#include <simgear/io/raw_socket.hxx>
+#include <simgear/timing/timestamp.hxx>
 
-using std::ostringstream;
+using namespace std;
+using namespace simgear;
+
+class MetarRequest : public HTTP::Request
+{
+public:
+    bool complete;
+    bool failed;
+    string metarData;
+    bool fromProxy;
+    
+    MetarRequest(const std::string& stationId) : 
+        HTTP::Request("http://weather.noaa.gov/pub/data/observations/metar/stations/" + stationId + ".TXT"),
+        complete(false),
+        failed(false)
+    {
+        fromProxy = false;
+    }
+    
+protected:
+    
+    virtual void responseHeader(const string& key, const string& value)
+    {
+        if (key == "x-metarproxy") {
+            fromProxy = true;
+        }
+    }
+
+    virtual void gotBodyData(const char* s, int n)
+    {
+        metarData += string(s, n);
+    }
+
+    virtual void responseComplete()
+    {
+        if (responseCode() == 200) {
+            complete = true;
+        } else {
+            SG_LOG(SG_ENVIRONMENT, SG_WARN, "metar download failed:" << url() << ": reason:" << responseReason());
+            failed = true;
+        }
+    }
+};
 
 // text color
-#if defined(__linux__) || defined( __sun__ ) ||defined(__CYGWIN__) || defined( __FreeBSD__ )
+#if defined(__linux__) || defined(__sun) || defined(__CYGWIN__) \
+    || defined( __FreeBSD__ ) || defined ( sgi )
 #      define R "\033[31;1m"           // red
 #      define G "\033[32;1m"           // green
 #      define Y "\033[33;1m"           // yellow
@@ -51,12 +103,6 @@ using std::ostringstream;
 #endif
 
 
-const char *azimuthName(double d);
-double rnd(double number, int digits);
-void printReport(SGMetar *m);
-void printVisibility(SGMetarVisibility *v);
-void printArgs(SGMetar *m, double airport_elevation);
-
 
 const char *azimuthName(double d)
 {
@@ -79,11 +125,11 @@ const char *azimuthName(double d)
 double rnd(double r, int g = 0)
 {
        double f = pow(10.0, g);
-       return f * rint(r / f);
+       return f * floor(r / f + 0.5);
 }
 
 
-ostream& operator<<(ostream& s, SGMetarVisibility& v)
+ostream& operator<<(ostream& s, const SGMetarVisibility& v)
 {
        ostringstream buf;
        int m = v.getModifier();
@@ -138,11 +184,9 @@ void printReport(SGMetar *m)
        // date/time
        int year = m->getYear();
        int month = m->getMonth();
-       cout << "Report time:\t\t";
-       if (year != -1 && month != -1)
-               cout << year << '/' << month << '/' << m->getDay();
+       cout << "Report time:\t\t" << year << '/' << month << '/' << m->getDay();
        cout << ' ' << m->getHour() << ':';
-       cout << std::setw(2) << std::setfill('0') << m->getMinute() << " UTC" << endl;
+       cout << setw(2) << setfill('0') << m->getMinute() << " UTC" << endl;
 
 
        // visibility
@@ -160,7 +204,7 @@ void printReport(SGMetar *m)
 
 
        // directed visibility
-       SGMetarVisibility *dirvis = m->getDirVisibility();
+       const SGMetarVisibility *dirvis = m->getDirVisibility();
        for (i = 0; i < 8; i++, dirvis++)
                if (dirvis->getVisibility_m() != NaN)
                        cout << "\t\t\t" << *dirvis << endl;
@@ -270,12 +314,12 @@ void printReport(SGMetar *m)
 
                // assemble surface string
                vector<string> surface;
-               if ((s = rwy.getDeposit()) && strlen(s))
+               if ((s = rwy.getDepositString()) && strlen(s))
                        surface.push_back(s);
                if ((s = rwy.getExtentString()) && strlen(s))
                        surface.push_back(s);
                if ((d = rwy.getDepth()) != NaN) {
-                       sprintf(buf, "%.0lf mm", d * 1000.0);
+                       sprintf(buf, "%.1lf mm", d * 1000.0);
                        surface.push_back(buf);
                }
                if ((s = rwy.getFrictionString()) && strlen(s))
@@ -422,7 +466,7 @@ void printArgs(SGMetar *m, double airport_elevation)
        
 
        // output everything
-       cout << "fgfs" << endl;
+       //cout << "fgfs" << endl;
        vector<string>::iterator arg;
        for (i = 0, arg = args.begin(); arg != args.end(); i++, arg++) {
                cout << "\t" << *arg << endl;
@@ -432,47 +476,145 @@ void printArgs(SGMetar *m, double airport_elevation)
 }
 
 
+void getproxy(string& host, string& port)
+{
+       host = "";
+       port = "80";
+
+       const char *p = getenv("http_proxy");
+       if (!p)
+               return;
+       while (isspace(*p))
+               p++;
+       if (!strncmp(p, "http://", 7))
+               p += 7;
+       if (!*p)
+               return;
+
+       char s[256], *t;
+       strncpy(s, p, 255);
+       s[255] = '\0';
+
+       for (t = s + strlen(s); t > s; t--)
+               if (!isspace(t[-1]) && t[-1] != '/')
+                       break;
+       *t = '\0';
+
+       t = strchr(s, ':');
+       if (t) {
+               *t++ = '\0';
+               port = t;
+       }
+       host = s;
+}
 
 
-
-const char *metar_list[] = {
-       "LOWW", "VHHH", "ULLI", "EHTW", "EFHK", "CYXU", 0, // note the trailing zero
-       "CYGK", "CYOW", "CYQY", "CYTZ", "CYXU", "EBBR", "EDDB", "EDDK", "EDVE", "EFHF",
-       "EFHK", "EGLC", "EGLL", "EHTW", "EIDW", "ENGM", "GMMN", "KART", "KBFI", "KBOS",
-       "KCCR", "KCEZ", "KCOF", "KDAL", "KDEN", "KDSM", "KEDW", "KEMT", "KENW", "KHON",
-       "KIGM", "KJFK", "KLAX", "KMCI", "KMKE", "KMLB", "KMSY", "KNBC", "KOAK", "KORD",
-       "KPNE", "KSAC", "KSAN", "KSEA", "KSFO", "KSJC", "KSMF", "KSMO", "KSNS", "KSQL",
-       "KSUN", "LBSF", "LEMD", "LFPG", "LFPO", "LGAT", "LHBP", "LIPQ", "LIRA", "LKPR",
-       "LLJR", "LOWG", "LOWI", "LOWK", "LOWL", "LOWS", "LOWW", "LOWZ", "LOXA", "LOXT",
-       "LOXZ", "LSZH", "LYBE", "NZWP", "ORBS", "PHNL", "ULLI", "VHHH", "WMKB", "YSSY",
-       0
-};
-
+void usage()
+{
+       printf(
+               "Usage: metar [-v] [-e elevation] [-r|-c] <list of ICAO airport ids or METAR strings>\n"
+               "       metar -h\n"
+               "\n"
+               "       -h|--help            show this help\n"
+               "       -v|--verbose         verbose output\n"
+               "       -r|--report          print report (default)\n"
+               "       -c|--command-line    print command line\n"
+               "       -e E|--elevation E   set airport elevation to E meters\n"
+               "                            (added to cloud bases in command line mode)\n"
+               "Environment:\n"
+               "       http_proxy           set proxy in the form \"http://host:port/\"\n"
+               "\n"
+               "Examples:\n"
+               "       $ metar ksfo koak\n"
+               "       $ metar -c ksfo -r ksfo\n"
+               "       $ metar \"LOWL 161500Z 19004KT 160V240 9999 FEW035 SCT300 29/23 Q1006 NOSIG\"\n"
+               "       $ fgfs  `metar -e 183 -c loww`\n"
+               "       $ http_proxy=http://localhost:3128/ metar ksfo\n"
+               "\n"
+       );
+}
 
 int main(int argc, char *argv[])
 {
-       const char **src = metar_list;
-       if (argc > 1)
-               src = (const char **)&argv[1];
-
-       for (int i = 0; src[i]; i++) {
-               const char *icao = src[i];
+       bool report = true;
+       bool verbose = false;
+       double elevation = 0.0;
 
-               try {
-                       SGMetar *m = new SGMetar(icao);
-                       //SGMetar *m = new SGMetar("2004/01/11 01:20\nLOWG 110120Z AUTO VRB01KT 0050 1600N R35/0600 FG M06/M06 Q1019 88//////\n");
-
-                       printf(G"INPUT: %s\n"N, m->getData());
-                       const char *unused = m->getUnusedData();
-                       if (*unused)
-                               printf(R"UNUSED: %s\n"N, unused);
+       if (argc <= 1) {
+               usage();
+               return 0;
+       }
 
-                       printReport(m);
-                       //printArgs(m, 0.0);
+       string proxy_host, proxy_port;
+       getproxy(proxy_host, proxy_port);
+
+  Socket::initSockets();
+  
+    HTTP::Client http;
+    http.setProxy(proxy_host, atoi(proxy_port.c_str()));
+    
+       for (int i = 1; i < argc; i++) {
+               if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
+                       usage();
+               else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose"))
+                       verbose = true;
+               else if (!strcmp(argv[i], "-r") || !strcmp(argv[i], "--report"))
+                       report = true;
+               else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--command-line"))
+                       report = false;
+               else if (!strcmp(argv[i], "-e") || !strcmp(argv[i], "--elevation")) {
+                       if (++i >= argc) {
+                               cerr << "-e option used without elevation" << endl;
+                               return 1;
+                       }
+                       elevation = strtod(argv[i], 0);
+               } else {
+                       static bool shown = false;
+                       if (verbose && !shown) {
+                               cerr << "Proxy host: '" << proxy_host << "'" << endl;
+                               cerr << "Proxy port: '" << proxy_port << "'" << endl << endl;
+                               shown = true;
+                       }
 
-                       delete m;
-               } catch (const sg_io_exception& e) {
-                       fprintf(stderr, R"ERROR: %s\n\n"N, e.getFormattedMessage().c_str());
+                       try {
+                MetarRequest* mr = new MetarRequest(argv[i]);
+                HTTP::Request_ptr own(mr);
+                http.makeRequest(mr);
+                
+            // spin until the request completes, fails or times out
+                SGTimeStamp start(SGTimeStamp::now());
+                while (start.elapsedMSec() <  8000) {
+                    http.update();
+                    if (mr->complete || mr->failed) {
+                        break;
+                    }
+                    SGTimeStamp::sleepForMSec(1);
+                }
+                
+                if (!mr->complete) {
+                    throw sg_io_exception("metar download failed (or timed out)");
+                }
+                               SGMetar *m = new SGMetar(mr->metarData);
+                               
+                               //SGMetar *m = new SGMetar("2004/01/11 01:20\nLOWG 110120Z AUTO VRB01KT 0050 1600N R35/0600 FG M06/M06 Q1019 88//////\n");
+
+                               if (verbose) {
+                                       cerr << G"INPUT: " << m->getData() << ""N << endl;
+
+                                       const char *unused = m->getUnusedData();
+                                       if (*unused)
+                                               cerr << R"UNUSED: " << unused << ""N << endl;
+                               }
+
+                               if (report)
+                                       printReport(m);
+                               else
+                                       printArgs(m, elevation);
+
+                               delete m;
+                       } catch (const sg_io_exception& e) {
+                               cerr << R"ERROR: " << e.getFormattedMessage().c_str() << ""N << endl << endl;
+                       }
                }
        }
        return 0;