From 7ffce3ac6af9df5c9437ac21d5f211edcbcadd8f Mon Sep 17 00:00:00 2001
From: ehofman <ehofman>
Date: Mon, 2 Feb 2004 10:14:20 +0000
Subject: [PATCH] Move the new metar class from FlightGear to SimGear

---
 src/Environment/Makefile.am                   |   12 +-
 src/Environment/metar.cxx                     | 1101 -----------------
 src/Environment/metar.hxx                     |  261 ----
 src/Main/Makefile.am                          |    9 +-
 .../metar-main.cxx => Main/metar_main.cxx}    |   61 +-
 5 files changed, 39 insertions(+), 1405 deletions(-)
 delete mode 100644 src/Environment/metar.cxx
 delete mode 100644 src/Environment/metar.hxx
 rename src/{Environment/metar-main.cxx => Main/metar_main.cxx} (89%)

diff --git a/src/Environment/Makefile.am b/src/Environment/Makefile.am
index fb7607919..e3f7450d1 100644
--- a/src/Environment/Makefile.am
+++ b/src/Environment/Makefile.am
@@ -7,16 +7,6 @@ noinst_LIBRARIES = libEnvironment.a
 libEnvironment_a_SOURCES = \
 	environment.cxx environment.hxx \
 	environment_mgr.cxx environment_mgr.hxx \
-	environment_ctrl.cxx environment_ctrl.hxx \
-	metar.cxx metar.hxx
-
-bin_PROGRAMS = metar
-
-metar_SOURCES = metar-main.cxx metar.cxx metar.hxx
-
-metar_LDADD = \
-	-lsgio -lsgbucket -lsgmisc -lsgstructure -lsgdebug \
-	-lplibnet -lplibul \
-	-lz $(base_LIBS)
+	environment_ctrl.cxx environment_ctrl.hxx
 
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
diff --git a/src/Environment/metar.cxx b/src/Environment/metar.cxx
deleted file mode 100644
index c99157fd7..000000000
--- a/src/Environment/metar.cxx
+++ /dev/null
@@ -1,1101 +0,0 @@
-// metar interface class
-//
-// Written by Melchior FRANZ, started December 2003.
-//
-// Copyright (C) 2003  Melchior FRANZ - mfranz@aon.at
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// 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
-//
-// $Id$
-
-/**
- * @file metar.cxx
- * Interface for encoded Metar aviation weather data.
- */
-
-#include <string>
-
-#include <simgear/io/sg_socket.hxx>
-#include <simgear/debug/logstream.hxx>
-#include <simgear/structure/exception.hxx>
-
-#include "metar.hxx"
-
-#define NaN FGMetarNaN
-
-/**
- * The constructor takes a Metar string, or a four-letter ICAO code. In the
- * latter case the metar string is downloaded from
- * http://weather.noaa.gov/pub/data/observations/metar/stations/.
- * The constructor throws sg_io_exceptions on failure. The "METAR"
- * keyword has no effect (apart from incrementing the group counter
- * @a grpcount) and can be left away. A keyword "SPECI" is
- * likewise accepted.
- *
- * @par Examples:
- * @code
- * Metar *m = new Metar("METAR KSFO 061656Z 19004KT 9SM SCT100 OVC200 08/03 A3013");
- * double t = m->getTemperature();
- * delete m;
- *
- * Metar n("KSFO");
- * double d = n.getDewpoint_C();
- * @endcode
- */
-Metar::Metar(const char *m) :
-	_grpcount(0),
-	_year(-1),
-	_month(-1),
-	_day(-1),
-	_hour(-1),
-	_minute(-1),
-	_report_type(-1),
-	_wind_dir(-1),
-	_wind_speed(NaN),
-	_gust_speed(NaN),
-	_wind_range_from(-1),
-	_wind_range_to(-1),
-	_temp(NaN),
-	_dewp(NaN),
-	_pressure(NaN)
-{
-	int i;
-	if (isalpha(m[0]) && isalpha(m[1]) && isalpha(m[2]) && isalpha(m[3]) && !m[4]) {
-		for (i = 0; i < 4; i++)
-			_icao[i] = toupper(m[i]);
-		_icao[4] = '\0';
-		_data = loadData(_icao);
-	} else {
-		_data = new char[strlen(m) + 1];
-		strcpy(_data, m);
-	}
-	normalizeData();
-
-	_m = _data;
-	_icao[0] = '\0';
-
-	// NOAA preample
-	scanPreambleDate();
-	scanPreambleTime();
-
-	// METAR header
-	scanType();
-	if (!scanId() || !scanDate())
-		throw sg_io_exception("metar data incomplete");
-	scanModifier();
-
-	// base set
-	scanWind();
-	scanVariability();
-	while (scanVisibility()) ;
-	while (scanRwyVisRange()) ;
-	while (scanWeather()) ;
-	while (scanSkyCondition()) ;
-	scanTemperature();
-	scanPressure();
-	while (scanSkyCondition()) ;
-	while (scanRunwayReport()) ;
-	scanWindShear();
-
-	// appendix
-	while (scanColorState()) ;
-	scanTrendForecast();
-	while (scanRunwayReport()) ;
-	scanRemainder();
-	scanRemark();
-
-	if (_grpcount < 4)
-		throw sg_io_exception("metar data invalid");
-}
-
-
-/**
-  * Clears lists and maps to discourage access after destruction.
-  */
-Metar::~Metar()
-{
-	_clouds.clear();
-	_runways.clear();
-	_weather.clear();
-	delete[] _data;
-}
-
-
-/**
-  * If called with "KSFO" loads data from
-  * @code
-  * http://weather.noaa.gov/pub/data/observations/metar/stations/KSFO.TXT.
-  * @endcode
-  * Throws sg_io_exception on failure. Gives up after waiting longer than 10 seconds.
-  *
-  * @param id four-letter ICAO Metar station code, e.g. "KSFO".
-  * @return pointer to Metar data string, allocated by new char[].
-  */
-char *Metar::loadData(const char *id)
-{
-	string host = "weather.noaa.gov";
-	string path = "/pub/data/observations/metar/stations/";
-	path += string(id) + ".TXT";
-	string get = string("GET ") + path + " HTTP/1.0\r\n\r\n";
-
-	SGSocket *sock = new SGSocket(host, "80", "tcp");
-	sock->set_timeout(10000);
-	if (!sock->open(SG_IO_OUT)) {
-		delete sock;
-		string err = "failed to load metar data from http://" + host + path;
-		throw sg_io_exception(err);
-	}
-
-	sock->writestring(get.c_str());
-
-	int i;
-	const int buflen = 512;
-	char buf[2 * buflen];
-
-	// skip HTTP header
-	while ((i = sock->readline(buf, buflen)))
-		if (i <= 2 && isspace(buf[0]) && (!buf[1] || isspace(buf[1])))
-			break;
-	if (i) {
-		i = sock->readline(buf, buflen);
-		if (i)
-			sock->readline(&buf[i], buflen);
-	}
-
-	sock->close();
-	delete sock;
-
-	char *metar = new char[strlen(buf) + 1];
-	strcpy(metar, buf);
-	return metar;
-}
-
-
-/**
-  * Replace any number of subsequent spaces by just one space.
-  * This makes scanning for things like "ALL RWY" easier.
-  */
-void Metar::normalizeData()
-{
-	char *src, *dest;
-	for (src = dest = _data; (*dest++ = *src++); )
-		while (*src == ' ' && src[1] == ' ')
-			src++;
-}
-
-
-// \d\d\d\d/\d\d/\d\d
-bool Metar::scanPreambleDate()
-{
-	char *m = _m;
-	int year, month, day;
-	if (!scanNumber(&m, &year, 4))
-		return false;
-	if (*m++ != '/')
-		return false;
-	if (!scanNumber(&m, &month, 2))
-		return false;
-	if (*m++ != '/')
-		return false;
-	if (!scanNumber(&m, &day, 2))
-		return false;
-	if (!scanBoundary(&m))
-		return false;
-	_year = year;
-	_month = month;
-	_day = day;
-	_m = m;
-	return true;
-}
-
-
-// \d\d:\d\d
-bool Metar::scanPreambleTime()
-{
-	char *m = _m;
-	int hour, minute;
-	if (!scanNumber(&m, &hour, 2))
-		return false;
-	if (*m++ != ':')
-		return false;
-	if (!scanNumber(&m, &minute, 2))
-		return false;
-	if (!scanBoundary(&m))
-		return false;
-	_hour = hour;
-	_minute = minute;
-	_m = m;
-	return true;
-}
-
-
-// (METAR|SPECI)
-bool Metar::scanType()
-{
-	if (strncmp(_m, "METAR ", 6) && strncmp(_m, "SPECI ", 6))
-		return false;
-	_m += 6;
-	_grpcount++;
-	return true;
-}
-
-
-// [A-Z]{4}
-bool Metar::scanId()
-{
-	char *m = _m;
-	if (!(isupper(*m++) && isupper(*m++) && isupper(*m++) && isupper(*m++)))
-		return false;
-	if (!scanBoundary(&m))
-		return false;
-	strncpy(_icao, _m, 4);
-	_icao[4] = '\0';
-	_m = m;
-	_grpcount++;
-	return true;
-}
-
-
-// \d{6}Z
-bool Metar::scanDate()
-{
-	char *m = _m;
-	int day, hour, minute;
-	if (!scanNumber(&m, &day, 2))
-		return false;
-	if (!scanNumber(&m, &hour, 2))
-		return false;
-	if (!scanNumber(&m, &minute, 2))
-		return false;
-	if (*m++ != 'Z')
-		return false;
-	if (!scanBoundary(&m))
-		return false;
-	_day = day;
-	_hour = hour;
-	_minute = minute;
-	_m = m;
-	_grpcount++;
-	return true;
-}
-
-
-// (NIL|AUTO|COR|RTD)
-bool Metar::scanModifier()
-{
-	char *m = _m;
-	int type;
-	if (!strncmp(m, "NIL", 3)) {
-		_m += strlen(_m);
-		return true;
-	}
-	if (!strncmp(m, "AUTO", 4))			// automatically generated
-		m += 4, type = AUTO;
-	else if (!strncmp(m, "COR", 3))			// manually corrected
-		m += 3, type = COR;
-	else if (!strncmp(m, "RTD", 3))			// routine delayed
-		m += 3, type = RTD;
-	else
-		return false;
-	if (!scanBoundary(&m))
-		return false;
-	_report_type = type;
-	_m = m;
-	_grpcount++;
-	return true;
-}
-
-
-// (\d{3}|VRB)\d{1,3}(G\d{2,3})?(KT|KMH|MPS)
-bool Metar::scanWind()
-{
-	char *m = _m;
-	int dir;
-	if (!strncmp(m, "VRB", 3))
-		m += 3, dir = -1;
-	else if (!scanNumber(&m, &dir, 3))
-		return false;
-
-	int i;
-	if (!scanNumber(&m, &i, 2, 3))
-		return false;
-	double speed = i;
-
-	double gust = NaN;
-	if (*m == 'G') {
-		m++;
-		if (!scanNumber(&m, &i, 2, 3))
-			return false;
-		gust = i;
-	}
-	double factor;
-	if (!strncmp(m, "KT", 2))
-		m += 2, factor = SG_KT_TO_MPS;
-	else if (!strncmp(m, "KMH", 3))
-		m += 3, factor = SG_KMH_TO_MPS;
-	else if (!strncmp(m, "KPH", 3))		// ??
-		m += 3, factor = SG_KMH_TO_MPS;
-	else if (!strncmp(m, "MPS", 3))
-		m += 3, factor = 1.0;
-	else
-		return false;
-	if (!scanBoundary(&m))
-		return false;
-	_m = m;
-	_wind_dir = dir;
-	_wind_speed = speed * factor;
-	if (gust != NaN)
-		_gust_speed = gust * factor;
-	_grpcount++;
-	return false;
-}
-
-
-// \d{3}V\d{3}
-bool Metar::scanVariability()
-{
-	char *m = _m;
-	int from, to;
-	if (!scanNumber(&m, &from, 3))
-		return false;
-	if (*m++ != 'V')
-		return false;
-	if (!scanNumber(&m, &to, 3))
-		return false;
-	if (!scanBoundary(&m))
-		return false;
-	_m = m;
-	_wind_range_from = from;
-	_wind_range_to = to;
-	_grpcount++;
-	return true;
-}
-
-
-bool Metar::scanVisibility()
-// TODO: if only directed vis are given, do still set min/max
-{
-	char *m = _m;
-	double distance;
-	int i, dir = -1;
-	int modifier = FGMetarVisibility::EQUALS;
-// \d{4}(N|NE|E|SE|S|SW|W|NW)?
-	if (scanNumber(&m, &i, 4)) {
-		if (*m == 'E')
-			m++, dir = 90;
-		else if (*m == 'W')
-			m++, dir = 270;
-		else if (*m == 'N') {
-			m++;
-			if (*m == 'E')
-				m++, dir = 45;
-			else if (*m == 'W')
-				m++, dir = 315;
-			else
-				dir = 0;
-		} else if (*m == 'S') {
-			m++;
-			if (*m == 'E')
-				m++, dir = 135;
-			else if (*m == 'W')
-				m++, dir = 225;
-			else
-				dir = 180;
-		}
-		if (i == 0)
-			i = 50, modifier = FGMetarVisibility::LESS_THAN;
-		else if (i == 9999)
-			i++, modifier = FGMetarVisibility::GREATER_THAN;
-		distance = i;
-	} else {
-// M?(\d{1,2}|\d{1,2}/\d{1,2}|\d{1,2} \d{1,2}/\d{1,2})(SM|KM)
-		modifier = 0;
-		if (*m == 'M')
-			m++, modifier = FGMetarVisibility::LESS_THAN;
-
-		if (!scanNumber(&m, &i, 1, 2))
-			return false;
-		distance = i;
-
-		if (*m == '/') {
-			m++;
-			if (!scanNumber(&m, &i, 1, 2))
-				return false;
-			distance /= i;
-		} else if (*m == ' ') {
-			m++;
-			int denom;
-			if (!scanNumber(&m, &i, 1, 2))
-				return false;
-			if (*m++ != '/')
-				return false;
-			if (!scanNumber(&m, &denom, 1, 2))
-				return false;
-			distance += (double)i / denom;
-		}
-
-		if (!strncmp(m, "SM", 2))
-			distance *= SG_SM_TO_METER, m += 2;
-		else if (!strncmp(m, "KM", 2))
-			distance *= 1000, m += 2;
-		else
-			return false;
-	}
-	if (!scanBoundary(&m))
-		return false;
-
-	FGMetarVisibility *v;
-	if (dir != -1)
-		v = &_dir_visibility[dir / 45];
-	else if (_min_visibility._distance == NaN)
-		v = &_min_visibility;
-	else
-		v = &_max_visibility;
-
-	v->_distance = distance;
-	v->_modifier = modifier;
-	v->_direction = dir;
-	_m = m;
-	_grpcount++;
-	return true;
-}
-
-
-// R\d\d[LCR]?/([PM]?\d{4}V)?[PM]?\d{4}(FT)?[DNU]?
-bool Metar::scanRwyVisRange()
-{
-	char *m = _m;
-	int i;
-	FGMetarRunway r;
-	if (*m++ != 'R')
-		return false;
-	if (!scanNumber(&m, &i, 2))
-		return false;
-	if (*m == 'L' || *m == 'C' || *m == 'R')
-		m++;
-
-	char id[4];
-	strncpy(id, _m + 1, i = m - _m - 1);
-	id[i] = '\0';
-
-	if (*m++ != '/')
-		return false;
-
-	int from, to;
-	if (*m == 'P')
-		m++, r._min_visibility._modifier = FGMetarVisibility::GREATER_THAN;
-	else if (*m == 'M')
-		m++, r._min_visibility._modifier = FGMetarVisibility::LESS_THAN;
-	if (!scanNumber(&m, &from, 4))
-		return false;
-	if (*m == 'V') {
-		m++;
-		if (*m == 'P')
-			m++, r._max_visibility._modifier = FGMetarVisibility::GREATER_THAN;
-		else if (*m == 'M')
-			m++, r._max_visibility._modifier = FGMetarVisibility::LESS_THAN;
-		if (!scanNumber(&m, &to, 4))
-			return false;
-	} else
-		to = from;
-
-	if (!strncmp(m, "FT", 2)) {
-		from = int(from * SG_FEET_TO_METER);
-		to = int(to * SG_FEET_TO_METER);
-		m += 2;
-	}
-	r._min_visibility._distance = from;
-	r._max_visibility._distance = to;
-
-	if (*m == '/')					// this is not in the spec!
-		*m++;
-	if (*m == 'D')
-		m++, r._min_visibility._tendency = FGMetarVisibility::DECREASING;
-	else if (*m == 'N')
-		m++, r._min_visibility._tendency = FGMetarVisibility::STABLE;
-	else if (*m == 'U')
-		m++, r._min_visibility._tendency = FGMetarVisibility::INCREASING;
-
-	if (!scanBoundary(&m))
-		return false;
-	_m = m;
-
-	_runways[id]._min_visibility = r._min_visibility;
-	_runways[id]._max_visibility = r._max_visibility;
-	_grpcount++;
-	return true;
-}
-
-
-static const struct Token special[] = {
-	"NSW",	"no significant weather",
-	"VCSH",	"showers in the vicinity",
-	"VCTS",	"thunderstorm in the vicinity",
-	0, 0
-};
-
-
-static const struct Token description[] = {
-	"SH",	"showers of",
-	"TS",	"thunderstorm with",
-	"BC",	"patches of",
-	"BL",	"blowing",
-	"DR",	"low drifting",
-	"FZ",	"freezing",
-	"MI",	"shallow",
-	"PR",	"partial",
-	0, 0
-};
-
-
-static const struct Token phenomenon[] = {
-	"DZ",	"drizzle",
-	"GR",	"hail",
-	"GS",	"small hail and/or snow pellets",
-	"IC",	"ice crystals",
-	"PE",	"ice pellets",
-	"RA",	"rain",
-	"SG",	"snow grains",
-	"SN",	"snow",
-	"UP",	"unknown precipitation",
-	"BR",	"mist",
-	"DU",	"widespread dust",
-	"FG",	"fog",
-	"FGBR",	"fog bank",
-	"FU",	"smoke",
-	"HZ",	"haze",
-	"PY",	"spray",
-	"SA",	"sand",
-	"VA",	"volcanic ash",
-	"DS",	"duststorm",
-	"FC",	"funnel cloud/tornado waterspout",
-	"PO",	"well-developed dust/sand whirls",
-	"SQ",	"squalls",
-	"SS",	"sandstorm",
-	"UP",	"unknown",	// ... due to failed automatic acquisition
-	0, 0
-};
-
-
-// (+|-|VC)?(NSW|MI|PR|BC|DR|BL|SH|TS|FZ)?((DZ|RA|SN|SG|IC|PE|GR|GS|UP){0,3})(BR|FG|FU|VA|DU|SA|HZ|PY|PO|SQ|FC|SS|DS){0,3}
-bool Metar::scanWeather()
-{
-	char *m = _m;
-	string weather;
-	const struct Token *a;
-	if ((a = scanToken(&m, special))) {
-		if (!scanBoundary(&m))
-			return false;
-		_weather.push_back(a->text);
-		_m = m;
-		return true;
-	}
-
-	string pre, post;
-	if (*m == '-')
-		m++, pre = "light ";
-	else if (*m == '+')
-		m++, pre = "heavy ";
-	else if (!strncmp(m, "VC", 2))
-		m += 2, post = "in the vicinity ";
-	else
-		pre = "moderate ";
-
-	int i;
-	for (i = 0; i < 3; i++) {
-		if (!(a = scanToken(&m, description)))
-			break;
-		weather += string(a->text) + " ";
-	}
-	for (i = 0; i < 3; i++) {
-		if (!(a = scanToken(&m, phenomenon)))
-			break;
-		weather += string(a->text) + " ";
-	}
-	if (!weather.length())
-		return false;
-	if (!scanBoundary(&m))
-		return false;
-	_m = m;
-	weather = pre + weather + post;
-	weather.erase(weather.length() - 1);
-	_weather.push_back(weather);
-	_grpcount++;
-	return true;
-}
-
-
-static const struct Token cloud_types[] = {
-	"AC",	 "altocumulus",
-	"ACC",	 "altocumulus castellanus",
-	"ACSL",	 "altocumulus standing lenticular",
-	"AS",	 "altostratus",
-	"CB",	 "cumulonimbus",
-	"CBMAM", "cumulonimbus mammatus",
-	"CC",	 "cirrocumulus",
-	"CCSL",	 "cirrocumulus standing lenticular",
-	"CI",	 "cirrus",
-	"CS",	 "cirrostratus",
-	"CU",	 "cumulus",
-	"CUFRA", "cumulus fractus",
-	"NS",	 "nimbostratus",
-	"SAC",	 "stratoaltocumulus",		// guessed
-	"SC",	 "stratocumulus",
-	"SCSL",	 "stratocumulus standing lenticular",
-	"ST",	 "stratus",
-	"STFRA", "stratus fractus",
-	"TCU",	 "towering cumulus",
-	0, 0
-};
-
-
-// (FEW|SCT|BKN|OVC|SKC|CLR|CAVOK|VV)([0-9]{3}|///)?[:cloud_type:]?
-bool Metar::scanSkyCondition()
-{
-	char *m = _m;
-	int i;
-	FGMetarCloud cl;
-
-	if (!strncmp(m, "CLR", i = 3)				// clear
-			|| !strncmp(m, "SKC", i = 3)		// sky clear
-			|| !strncmp(m, "NSC", i = 3)		// no significant clouds
-			|| !strncmp(m, "CAVOK", i = 5))	{	// ceiling and visibility OK (implies 9999)
-		m += i;
-		if (!scanBoundary(&m))
-			return false;
-		cl._coverage = 0;
-		_clouds.push_back(cl);
-		_m = m;
-		return true;
-	}
-
-	if (!strncmp(m, "VV", i = 2))				// vertical visibility
-		;
-	else if (!strncmp(m, "FEW", i = 3))
-		cl._coverage = 1;
-	else if (!strncmp(m, "SCT", i = 3))
-		cl._coverage = 2;
-	else if (!strncmp(m, "BKN", i = 3))
-		cl._coverage = 3;
-	else if (!strncmp(m, "OVC", i = 3))
-		cl._coverage = 4;
-	else
-		return false;
-	m += i;
-
-	if (!strncmp(m, "///", 3))	// vis not measurable (e.g. because of heavy snowing)
-		m += 3, i = -1;
-	else if (scanBoundary(&m)) {
-		_m = m;
-		return true;				// ignore single OVC/BKN/...
-	} else if (!scanNumber(&m, &i, 3))
-		i = -1;
-
-	if (cl._coverage == -1) {
-		if (!scanBoundary(&m))
-			return false;
-		if (i == -1)			// 'VV///'
-			_vert_visibility._modifier = FGMetarVisibility::NOGO;
-		else
-			_vert_visibility._distance = i * 100 * SG_FEET_TO_METER;
-		_m = m;
-		return true;
-	}
-
-	if (i != -1)
-		cl._altitude = i * 100 * SG_FEET_TO_METER;
-
-	const struct Token *a;
-	if ((a = scanToken(&m, cloud_types))) {
-		cl._type = a->id;
-		cl._type_long = a->text;
-	}
-	if (!scanBoundary(&m))
-		return false;
-	_clouds.push_back(cl);
-	_m = m;
-	_grpcount++;
-	return true;
-}
-
-
-// M?[0-9]{2}/(M?[0-9]{2})?            (spec)
-// (M?[0-9]{2}|XX)/(M?[0-9]{2}|XX)?    (Namibia)
-bool Metar::scanTemperature()
-{
-	char *m = _m;
-	int sign = 1, temp, dew;
-	if (!strncmp(m, "XX/XX", 5)) {		// not spec compliant!
-		_m += 5;
-		return scanBoundary(&_m);
-	}
-
-	if (*m == 'M')
-		m++, sign = -1;
-	if (!scanNumber(&m, &temp, 2))
-		return false;
-	temp *= sign;
-
-	if (*m++ != '/')
-		return false;
-	if (!scanBoundary(&m)) {
-		if (!strncmp(m, "XX", 2))	// not spec compliant!
-			m += 2, sign = 0;
-		else {
-			sign = 1;
-			if (*m == 'M')
-				m++, sign = -1;
-			if (!scanNumber(&m, &dew, 2))
-				return false;
-		}
-		if (!scanBoundary(&m))
-			return false;
-		if (sign)
-			_dewp = sign * dew;
-	}
-	_temp = temp;
-	_m = m;
-	_grpcount++;
-	return true;
-}
-
-
-double Metar::getRelHumidity() const
-{
-	if (_temp == NaN || _dewp == NaN)
-		return NaN;
-	double dewp = pow(10, 7.5 * _dewp / (237.7 + _dewp));
-	double temp = pow(10, 7.5 * _temp / (237.7 + _temp));
-	return dewp * 100 / temp;
-}
-
-
-// [AQ]\d{4}             (spec)
-// [AQ]\d{2}(\d{2}|//)   (Namibia)
-bool Metar::scanPressure()
-{
-	char *m = _m;
-	double factor;
-	int press, i;
-
-	if (*m == 'A')
-		factor = SG_INHG_TO_PA / 100;
-	else if (*m == 'Q')
-		factor = 100;
-	else
-		return false;
-	m++;
-	if (!scanNumber(&m, &press, 2))
-		return false;
-	press *= 100;
-	if (!strncmp(m, "//", 2))	// not spec compliant!
-		m += 2;
-	else if (scanNumber(&m, &i, 2))
-		press += i;
-	else
-		return false;
-	if (!scanBoundary(&m))
-		return false;
-	_pressure = press * factor;
-	_m = m;
-	_grpcount++;
-	return true;
-}
-
-
-static const char *runway_deposit[] = {
-	"clear and dry",
-	"damp",
-	"wet or puddles",
-	"frost",
-	"dry snow",
-	"wet snow",
-	"slush",
-	"ice",
-	"compacted snow",
-	"frozen ridges"
-};
-
-
-static const char *runway_deposit_extent[] = {
-	0, "1-10%", "11-25%", 0, 0, "26-50%", 0, 0, 0, "51-100%"
-};
-
-
-static const char *runway_friction[] = {
-	0,
-	"poor braking action",
-	"poor/medium braking action",
-	"medium braking action",
-	"medium/good braking action",
-	"good braking action",
-	0, 0, 0,
-	"friction: unreliable measurement"
-};
-
-
-// \d\d(CLRD|[\d/]{4})(\d\d|//)
-bool Metar::scanRunwayReport()
-{
-	char *m = _m;
-	int i;
-	char id[4];
-	FGMetarRunway r;
-
-	if (!scanNumber(&m, &i, 2))
-		return false;
-	if (i == 88)
-		strcpy(id, "ALL");
-	else if (i == 99)
-		strcpy(id, "REP");		// repetition of previous report
-	else if (i >= 50) {
-		i -= 50;
-		id[0] = i / 10 + '0', id[1] = i % 10 + '0', id[2] = 'R', id[3] = '\0';
-	} else
-		id[0] = i / 10 + '0', id[1] = i % 10 + '0', id[2] = '\0';
-
-	if (!strncmp(m, "CLRD", 4)) {
-		m += 4;							// runway cleared
-		r._deposit = "cleared";
-	} else {
-		if (scanNumber(&m, &i, 1)) {
-			r._deposit = runway_deposit[i];
-		} else if (*m == '/')
-			m++;
-		else
-			return false;
-		if (*m == '1' || *m == '2' || *m == '5' || *m == '9') {	// extent of deposit
-			r._extent = *m - '0';
-			r._extent_string = runway_deposit_extent[*m - '0'];
-		} else if (*m != '/')
-			return false;
-		m++;
-		i = -1;
-		if (!strncmp(m, "//", 2))
-			m += 2;
-		else if (!scanNumber(&m, &i, 2))
-			return false;
-
-		if (i == 0)
-			r._depth = 0.5;					// < 1 mm deep (let's say 0.5 :-)
-		else if (i > 0 && i <= 90)
-			r._depth = i / 1000.0;				// i mm deep
-		else if (i >= 92 && i <= 98)
-			r._depth = (i - 90) / 20.0;
-		else if (i == 99)
-			r._comment = "runway not in use";
-		else if (i == -1)					// no depth given ("//")
-			;
-		else
-			return false;
-	}
-	i = -1;
-	if (m[0] == '/' && m[1] == '/')
-		m += 2;
-	else if (!scanNumber(&m, &i, 2))
-		return false;
-	if (i >= 1 && i < 90) {
-		r._friction = i / 100.0;
-	} else if ((i >= 91 && i <= 95) || i == 99) {
-		r._friction_string = runway_friction[i - 90];
-	}
-	if (!scanBoundary(&m))
-		return false;
-
-	_runways[id]._deposit = r._deposit;
-	_runways[id]._extent = r._extent;
-	_runways[id]._extent_string = r._extent_string;
-	_runways[id]._depth = r._depth;
-	_runways[id]._friction = r._friction;
-	_runways[id]._friction_string = r._friction_string;
-	_runways[id]._comment = r._comment;
-	_m = m;
-	_grpcount++;
-	return true;
-}
-
-
-// WS (ALL RWYS?|RWY ?\d\d[LCR]?)?
-bool Metar::scanWindShear()
-{
-	char *m = _m;
-	if (strncmp(m, "WS", 2))
-		return false;
-	m += 2;
-	if (!scanBoundary(&m))
-		return false;
-
-	if (!strncmp(m, "ALL", 3)) {
-		m += 3;
-		if (!scanBoundary(&m))
-			return false;
-		if (strncmp(m, "RWY", 3))
-			return false;
-		m += 3;
-		if (*m == 'S')
-			m++;
-		if (!scanBoundary(&m))
-			return false;
-		_runways["ALL"]._wind_shear = true;
-		_m = m;
-		return true;
-	}
-
-	char id[4], *mm;
-	int i, cnt;
-	for (cnt = 0;; cnt++) {			// ??
-		if (strncmp(m, "RWY", 3))
-			break;
-		m += 3;
-		scanBoundary(&m);
-		mm = m;
-		if (!scanNumber(&m, &i, 2))
-			return false;
-		if (*m == 'L' || *m == 'C' || *m == 'R')
-			m++;
-		strncpy(id, mm, i = m - mm);
-		id[i] = '\0';
-		if (!scanBoundary(&m))
-			return false;
-		_runways[id]._wind_shear = true;
-	}
-	if (!cnt)
-		_runways["ALL"]._wind_shear = true;
-	_m = m;
-	return true;
-}
-
-
-bool Metar::scanTrendForecast()
-{
-	char *m = _m;
-	if (strncmp(m, "NOSIG", 5))
-		return false;
-
-	m += 5;
-	if (!scanBoundary(&m))
-		return false;
-	_m = m;
-	return true;
-}
-
-
-// (BLU|WHT|GRN|YLO|AMB|RED)
-static const struct Token colors[] = {
-	"BLU", "Blue",		// 2500 ft,  8.0 km
-	"WHT", "White",		// 1500 ft,  5.0 km
-	"GRN", "Green",		//  700 ft,  3.7 km
-	"YLO", "Yellow",	//  300 ft,  1.6 km
-	"AMB", "Amber",		//  200 ft,  0.8 km
-	"RED", "Red",		// <200 ft, <0.8 km
-	0, 0
-};
-
-
-bool Metar::scanColorState()
-{
-	char *m = _m;
-	const struct Token *a;
-	if (!(a = scanToken(&m, colors)))
-		return false;
-	if (!scanBoundary(&m))
-		return false;
-	//printf(Y"Code %s\n"N, a->text);
-	_m = m;
-	return true;
-}
-
-
-bool Metar::scanRemark()
-{
-	if (strncmp(_m, "RMK", 3))
-		return false;
-	_m += 3;
-	if (!scanBoundary(&_m))
-		return false;
-
-	while (*_m) {
-		if (!scanRunwayReport()) {
-			while (*_m && !isspace(*_m))
-				_m++;
-			scanBoundary(&_m);
-		}
-	}
-	return true;
-}
-
-
-bool Metar::scanRemainder()
-{
-	char *m = _m;
-	if (!(strncmp(m, "NOSIG", 5))) {
-		m += 5;
-		if (scanBoundary(&m))
-			_m = m; //_comment.push_back("No significant tendency");
-	}
-
-	if (!scanBoundary(&m))
-		return false;
-	_m = m;
-	return true;
-}
-
-
-bool Metar::scanBoundary(char **s)
-{
-	if (**s && !isspace(**s))
-		return false;
-	while (isspace(**s))
-		(*s)++;
-	return true;
-}
-
-
-int Metar::scanNumber(char **src, int *num, int min, int max)
-{
-	int i;
-	char *s = *src;
-	*num = 0;
-	for (i = 0; i < min; i++) {
-		if (!isdigit(*s))
-			return 0;
-		else
-			*num = *num * 10 + *s++ - '0';
-	}
-	for (; i < max && isdigit(*s); i++)
-		*num = *num * 10 + *s++ - '0';
-	*src = s;
-	return i;
-}
-
-
-// find longest match of str in list
-const struct Token *Metar::scanToken(char **str, const struct Token *list)
-{
-	const struct Token *longest = 0;
-	int maxlen = 0, len;
-	char *s;
-	for (int i = 0; (s = list[i].id); i++) {
-		len = strlen(s);
-		if (!strncmp(s, *str, len) && len > maxlen) {
-			maxlen = len;
-			longest = &list[i];
-		}
-	}
-	*str += maxlen;
-	return longest;
-}
-
-#undef NaN
diff --git a/src/Environment/metar.hxx b/src/Environment/metar.hxx
deleted file mode 100644
index 8dcb55705..000000000
--- a/src/Environment/metar.hxx
+++ /dev/null
@@ -1,261 +0,0 @@
-// metar interface class
-//
-// Written by Melchior FRANZ, started December 2003.
-//
-// Copyright (C) 2003  Melchior FRANZ - mfranz@aon.at
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// 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
-//
-// $Id$
-
-#ifndef _METAR_HXX
-#define _METAR_HXX
-
-#include <vector>
-#include <map>
-#include <string>
-
-#include <simgear/constants.h>
-
-SG_USING_STD(vector);
-SG_USING_STD(map);
-SG_USING_STD(string);
-
-const double FGMetarNaN = -1E20;
-#define NaN FGMetarNaN
-
-struct Token {
-	char	*id;
-	char	*text;
-};
-
-
-class Metar;
-
-class FGMetarVisibility {
-	friend class Metar;
-public:
-	FGMetarVisibility() :
-		_distance(NaN),
-		_direction(-1),
-		_modifier(EQUALS),
-		_tendency(NONE) {}
-
-	enum Modifier {
-		NOGO,
-		EQUALS,
-		LESS_THAN,
-		GREATER_THAN
-	};
-
-	enum Tendency {
-		NONE,
-		STABLE,
-		INCREASING,
-		DECREASING
-	};
-
-	inline double	getVisibility_m()	const { return _distance; }
-	inline double	getVisibility_ft()	const { return _distance == NaN ? NaN : _distance * SG_METER_TO_FEET; }
-	inline double	getVisibility_sm()	const { return _distance == NaN ? NaN : _distance * SG_METER_TO_SM; }
-	inline int	getDirection()		const { return _direction; }
-	inline int	getModifier()		const { return _modifier; }
-	inline int	getTendency()		const { return _tendency; }
-
-protected:
-	double	_distance;
-	int	_direction;
-	int	_modifier;
-	int	_tendency;
-};
-
-
-// runway condition (surface and visibility)
-class FGMetarRunway {
-	friend class Metar;
-public:
-	FGMetarRunway() :
-		_deposit(0),
-		_extent(-1),
-		_extent_string(0),
-		_depth(NaN),
-		_friction(NaN),
-		_friction_string(0),
-		_comment(0),
-		_wind_shear(false) {}
-
-	inline const char		*getDeposit()		const { return _deposit; }
-	inline double			getExtent()		const { return _extent; }
-	inline const char		*getExtentString()	const { return _extent_string; }
-	inline double			getDepth()		const { return _depth; }
-	inline double			getFriction()		const { return _friction; }
-	inline const char		*getFrictionString()	const { return _friction_string; }
-	inline const char		*getComment()		const { return _comment; }
-	inline const bool		getWindShear()		const { return _wind_shear; }
-	inline FGMetarVisibility	getMinVisibility()	const { return _min_visibility; }
-	inline FGMetarVisibility	getMaxVisibility()	const { return _max_visibility; }
-
-protected:
-	FGMetarVisibility _min_visibility;
-	FGMetarVisibility _max_visibility;
-	const char	*_deposit;
-	int		_extent;
-	const char	*_extent_string;
-	double		_depth;
-	double		_friction;
-	const char	*_friction_string;
-	const char	*_comment;
-	bool		_wind_shear;
-};
-
-
-// cloud layer
-class FGMetarCloud {
-	friend class Metar;
-public:
-	FGMetarCloud() :
-		_coverage(-1),
-		_altitude(NaN),
-		_type(0),
-		_type_long(0) {}
-
-	inline int	getCoverage()		const { return _coverage; }
-	inline double	getAltitude_m()		const { return _altitude; }
-	inline double	getAltitude_ft()	const { return _altitude == NaN ? NaN : _altitude * SG_METER_TO_FEET; }
-	inline char	*getTypeString()	const { return _type; }
-	inline char	*getTypeLongString()	const { return _type_long; }
-
-protected:
-	int	_coverage;		// quarters: 0 -> clear ... 4 -> overcast
-	double	_altitude;		// 1000 m
-	char	*_type;			// CU
-	char	*_type_long;		// cumulus
-};
-
-
-class Metar {
-public:
-	Metar(const char *m);
-	Metar(const string m) { Metar(m.c_str()); }
-	~Metar();
-
-	enum ReportType {
-		NONE,
-		AUTO,
-		COR,
-		RTD
-	};
-
-	inline const char *getData()		const { return _data; }
-	inline const char *getUnusedData()	const { return _m; }
-	inline const char *getId()		const { return _icao; }
-	inline int	getYear()		const { return _year; }
-	inline int	getMonth()		const { return _month; }
-	inline int	getDay()		const { return _day; }
-	inline int	getHour()		const { return _hour; }
-	inline int	getMinute()		const { return _minute; }
-	inline int	getReportType()		const { return _report_type; }
-
-	inline int	getWindDir()		const { return _wind_dir; }
-	inline double	getWindSpeed_mps()	const { return _wind_speed; }
-	inline double	getWindSpeed_kmh()	const { return _wind_speed == NaN ? NaN : _wind_speed * 3.6; }
-	inline double	getWindSpeed_kt()	const { return _wind_speed == NaN ? NaN : _wind_speed * SG_MPS_TO_KT; }
-	inline double	getWindSpeed_mph()	const { return _wind_speed == NaN ? NaN : _wind_speed * SG_MPS_TO_MPH; }
-
-	inline double	getGustSpeed_mps()	const { return _gust_speed; }
-	inline double	getGustSpeed_kmh()	const { return _gust_speed == NaN ? NaN : _gust_speed * 3.6; }
-	inline double	getGustSpeed_kt()	const { return _gust_speed == NaN ? NaN : _gust_speed * SG_MPS_TO_KT; }
-	inline double	getGustSpeed_mph()	const { return _gust_speed == NaN ? NaN : _gust_speed * SG_MPS_TO_MPH; }
-
-	inline int	getWindRangeFrom()	const { return _wind_range_from; }
-	inline int	getWindRangeTo()	const { return _wind_range_to; }
-
-	inline FGMetarVisibility& getMinVisibility()	{ return _min_visibility; }
-	inline FGMetarVisibility& getMaxVisibility()	{ return _max_visibility; }
-	inline FGMetarVisibility& getVertVisibility()	{ return _vert_visibility; }
-	inline FGMetarVisibility *getDirVisibility()	{ return _dir_visibility; }
-
-	inline double	getTemperature_C()	const { return _temp; }
-	inline double	getTemperature_F()	const { return _temp == NaN ? NaN : 1.8 * _temp + 32; }
-	inline double	getDewpoint_C()		const { return _dewp; }
-	inline double	getDewpoint_F()		const { return _dewp == NaN ? NaN : 1.8 * _dewp + 32; }
-	inline double	getPressure_hPa()	const { return _pressure == NaN ? NaN : _pressure / 100; }
-	inline double	getPressure_inHg()	const { return _pressure == NaN ? NaN : _pressure * SG_PA_TO_INHG; }
-
-	double		getRelHumidity()	const;
-
-	inline vector<FGMetarCloud>& getClouds()	{ return _clouds; }
-	inline map<string, FGMetarRunway>& getRunways()	{ return _runways; }
-	inline vector<string>& getWeather()		{ return _weather; }
-
-protected:
-	int	_grpcount;
-	char	*_data;
-	char	*_m;
-	char	_icao[5];
-	int	_year;
-	int	_month;
-	int	_day;
-	int	_hour;
-	int	_minute;
-	int	_report_type;
-	int	_wind_dir;
-	double	_wind_speed;
-	double	_gust_speed;
-	int	_wind_range_from;
-	int	_wind_range_to;
-	double	_temp;
-	double	_dewp;
-	double	_pressure;
-
-	FGMetarVisibility		_min_visibility;
-	FGMetarVisibility		_max_visibility;
-	FGMetarVisibility		_vert_visibility;
-	FGMetarVisibility		_dir_visibility[8];
-	vector<FGMetarCloud>		_clouds;
-	map<string, FGMetarRunway>	_runways;
-	vector<string>			_weather;
-
-	bool	scanPreambleDate();
-	bool	scanPreambleTime();
-
-	bool	scanType();
-	bool	scanId();
-	bool	scanDate();
-	bool	scanModifier();
-	bool	scanWind();
-	bool	scanVariability();
-	bool	scanVisibility();
-	bool	scanRwyVisRange();
-	bool	scanSkyCondition();
-	bool	scanWeather();
-	bool	scanTemperature();
-	bool	scanPressure();
-	bool	scanRunwayReport();
-	bool	scanWindShear();
-	bool	scanTrendForecast();
-	bool	scanColorState();
-	bool	scanRemark();
-	bool	scanRemainder();
-
-	int	scanNumber(char **str, int *num, int min, int max = 0);
-	bool	scanBoundary(char **str);
-	const struct Token *scanToken(char **str, const struct Token *list);
-	char	*loadData(const char *id);
-	void	normalizeData();
-};
-
-#undef NaN
-#endif // _METAR_HXX
diff --git a/src/Main/Makefile.am b/src/Main/Makefile.am
index c244aaf0f..dbc93968d 100644
--- a/src/Main/Makefile.am
+++ b/src/Main/Makefile.am
@@ -26,7 +26,7 @@ AM_CXXFLAGS = -DPKGLIBDIR=\"$(pkglibdir)\"
 
 EXTRA_DIST = 3dfx.sh runfgfs.in runfgfs.bat.in
 
-bin_PROGRAMS = fgfs
+bin_PROGRAMS = fgfs metar
 
 noinst_SCRIPTS = runfgfs.bat runfgfs
 
@@ -95,4 +95,11 @@ fgfs_LDADD = \
 	$(opengl_LIBS) \
 	$(audio_LIBS)
 
+metar_SOURCES = metar_main.cxx
+
+metar_LDADD = \
+        -lsgenvironment -lsgio -lsgbucket -lsgmisc -lsgstructure -lsgdebug \
+        -lplibnet -lplibul \
+        -lz $(base_LIBS)
+
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
diff --git a/src/Environment/metar-main.cxx b/src/Main/metar_main.cxx
similarity index 89%
rename from src/Environment/metar-main.cxx
rename to src/Main/metar_main.cxx
index 273320573..4fdc9dd95 100644
--- a/src/Environment/metar-main.cxx
+++ b/src/Main/metar_main.cxx
@@ -25,8 +25,7 @@
 
 #include <simgear/debug/logstream.hxx>
 #include <simgear/structure/exception.hxx>
-
-#include "metar.hxx"
+#include <simgear/environment/metar.hxx>
 
 using std::ostringstream;
 
@@ -54,9 +53,9 @@ using std::ostringstream;
 
 const char *azimuthName(double d);
 double rnd(double number, int digits);
-void printReport(Metar *m);
-void printVisibility(FGMetarVisibility *v);
-void printArgs(Metar *m, double airport_elevation);
+void printReport(SGMetar *m);
+void printVisibility(SGMetarVisibility *v);
+void printArgs(SGMetar *m, double airport_elevation);
 
 
 const char *azimuthName(double d)
@@ -84,14 +83,14 @@ double rnd(double r, int g = 0)
 }
 
 
-ostream& operator<<(ostream& s, FGMetarVisibility& v)
+ostream& operator<<(ostream& s, SGMetarVisibility& v)
 {
 	ostringstream buf;
 	int m = v.getModifier();
 	const char *mod;
-	if (m == FGMetarVisibility::GREATER_THAN)
+	if (m == SGMetarVisibility::GREATER_THAN)
 		mod = ">=";
-	else if (m == FGMetarVisibility::LESS_THAN)
+	else if (m == SGMetarVisibility::LESS_THAN)
 		mod = "<";
 	else
 		mod = "";
@@ -114,19 +113,19 @@ ostream& operator<<(ostream& s, FGMetarVisibility& v)
 }
 
 
-void printReport(Metar *m)
+void printReport(SGMetar *m)
 {
-#define NaN FGMetarNaN
+#define NaN SGMetarNaN
 	const char *s;
 	char buf[256];
 	double d;
 	int i, lineno;
 
-	if ((i = m->getReportType()) == Metar::AUTO)
+	if ((i = m->getReportType()) == SGMetar::AUTO)
 		s = "\t\t(automatically generated)";
-	else if (i == Metar::COR)
+	else if (i == SGMetar::COR)
 		s = "\t\t(manually corrected)";
-	else if (i == Metar::RTD)
+	else if (i == SGMetar::RTD)
 		s = "\t\t(routine delayed)";
 	else
 		s = "";
@@ -147,8 +146,8 @@ void printReport(Metar *m)
 
 
 	// visibility
-	FGMetarVisibility minvis = m->getMinVisibility();
-	FGMetarVisibility maxvis = m->getMaxVisibility();
+	SGMetarVisibility minvis = m->getMinVisibility();
+	SGMetarVisibility maxvis = m->getMaxVisibility();
 	double min = minvis.getVisibility_m();
 	double max = maxvis.getVisibility_m();
 	if (min != NaN) {
@@ -161,17 +160,17 @@ void printReport(Metar *m)
 
 
 	// directed visibility
-	FGMetarVisibility *dirvis = m->getDirVisibility();
+	SGMetarVisibility *dirvis = m->getDirVisibility();
 	for (i = 0; i < 8; i++, dirvis++)
 		if (dirvis->getVisibility_m() != NaN)
 			cout << "\t\t\t" << *dirvis << endl;
 
 
 	// vertical visibility
-	FGMetarVisibility vertvis = m->getVertVisibility();
+	SGMetarVisibility vertvis = m->getVertVisibility();
 	if ((d = vertvis.getVisibility_ft()) != NaN)
 		cout << "Vert. visibility:\t" << vertvis << endl;
-	else if (vertvis.getModifier() == FGMetarVisibility::NOGO)
+	else if (vertvis.getModifier() == SGMetarVisibility::NOGO)
 		cout << "Vert. visibility:\timpossible to determine" << endl;
 
 
@@ -241,8 +240,8 @@ void printReport(Metar *m)
 	const char *coverage_string[5] = {
 		"clear skies", "few clouds", "scattered clouds", "broken clouds", "sky overcast"
 	};
-	vector<FGMetarCloud> cv = m->getClouds();
-	vector<FGMetarCloud>::iterator cloud;
+	vector<SGMetarCloud> cv = m->getClouds();
+	vector<SGMetarCloud>::iterator cloud;
 	for (lineno = 0, cloud = cv.begin(); cloud != cv.end(); cloud++, lineno++) {
 		cout << (lineno ? "\t\t\t" : "Sky condition:\t\t");
 
@@ -259,15 +258,15 @@ void printReport(Metar *m)
 
 
 	// runways
-	map<string, FGMetarRunway> rm = m->getRunways();
-	map<string, FGMetarRunway>::iterator runway;
+	map<string, SGMetarRunway> rm = m->getRunways();
+	map<string, SGMetarRunway>::iterator runway;
 	for (runway = rm.begin(); runway != rm.end(); runway++) {
 		lineno = 0;
 		if (!strcmp(runway->first.c_str(), "ALL"))
 			cout << "All runways:\t\t";
 		else
 			cout << "Runway " << runway->first << ":\t\t";
-		FGMetarRunway rwy = runway->second;
+		SGMetarRunway rwy = runway->second;
 
 		// assemble surface string
 		vector<string> surface;
@@ -297,8 +296,8 @@ void printReport(Metar *m)
 		}
 
 		// assemble visibility string
-		FGMetarVisibility minvis = rwy.getMinVisibility();
-		FGMetarVisibility maxvis = rwy.getMaxVisibility();
+		SGMetarVisibility minvis = rwy.getMinVisibility();
+		SGMetarVisibility maxvis = rwy.getMaxVisibility();
 		if ((d = minvis.getVisibility_m()) != NaN) {
 			if (lineno++)
 				cout << endl << "\t\t\t";
@@ -321,9 +320,9 @@ void printReport(Metar *m)
 }
 
 
-void printArgs(Metar *m, double airport_elevation)
+void printArgs(SGMetar *m, double airport_elevation)
 {
-#define NaN FGMetarNaN
+#define NaN SGMetarNaN
 	vector<string> args;
 	char buf[256];
 	int i;
@@ -342,8 +341,8 @@ void printArgs(Metar *m, double airport_elevation)
 	const char *coverage_string[5] = {
 		"clear", "few", "scattered", "broken", "overcast"
 	};
-	vector<FGMetarCloud> cv = m->getClouds();
-	vector<FGMetarCloud>::iterator cloud;
+	vector<SGMetarCloud> cv = m->getClouds();
+	vector<SGMetarCloud>::iterator cloud;
 	for (i = 0, cloud = cv.begin(); i < 5; i++) {
 		int coverage = 0;
 		double altitude = -99999;
@@ -460,8 +459,8 @@ int main(int argc, char *argv[])
 		const char *icao = src[i];
 
 		try {
-			Metar *m = new Metar(icao);
-			//Metar *m = new Metar("2004/01/11 01:20\nLOWG 110120Z AUTO VRB01KT 0050 1600N R35/0600 FG M06/M06 Q1019 88//////\n");
+			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();