CSE 190 Sp 2000 -- Lecture 17 -- May 30, 2000


Administrivia

I'll be out of town at a meeting in D.C. Thursday. Matt Hohlfeld will be going over the sample solutions for assignment 3 then. Please print out a copy of the sample solutions and bring them to class.

New Material

In this lecture I went over the GPS coordinates extraction scripts. If you do not already know perl, looking through these two more-or-less equivalent scripts can be instructive.

addr_gps.sh

#!/bin/sh

PATH=/home/bsy/bin:/home/bsy/bin.`/home/bsy/bin/sys`:/usr/bin:/bin:/usr/local/bin:/usr/local/GNU/bin:/usr/local/X11/bin:/usr/X11R6/bin:/usr/local/netscape
export PATH

me=`basename $0`
usage="$0 [-c city] [-s state] [address]"
default_city='San Diego'
default_state='CA'
while :
do
	case $# in
	0)	break;;
	*)	case "$1" in
		-c)	case $# in
			1)	echo "$me:  City argument missing
$usage" >&2; exit 1;;
			esac
			city="$2"; ; ;;
		-s)	case $# in
			1)	echo "$me:  State argument missing
$usage" >&2; exit 1;;
			esac
			state="$2"; ; ;;
		-h|-?)	echo "$usage" >&2; exit 0;;
		-*)	echo "$me:  Unrecognized flag $1
$usage" >&2; exit 1;;
		*)	break;;
		esac;;
	esac
done
case $# in
0)	street_addr=`xcb -p 0 | tr '\n' ','`;;
*)	street_addr="$*";;
esac

case "$street_addr" in
*,)	street_addr=`echo $street_addr | sed 's/,$//'`;;
esac

# hack for use with my on-line phone book, where .HA starts home
# addresses and .WA starts work addresses.  phone -r outputs "raw"
# phonebook data which contains these data field tags.

case "$street_addr" in
.?A*)
	street_addr=`echo "$street_addr" | sed 's/^\.[^ 	]*A[ 	]//;s/,\.[^ 	]*A[ 	]/,/g'`
	;;
esac

# if not set by flags....  (We assume that users will either set both
# city and state by command line flags, or city only and use default state.)
#
case "x$city" in
x)
	case "$street_addr" in
	*,*)	# guess city state info encoded
		city=`expr "$street_addr" : '.*,\([^,]*\)'`
		# will probably get leading space, but back-end accepts that.
		# also may include zip code, which appears to be ignored by
		# the server at lycos.vicinity.com.
		street_addr=`expr "$street_addr" : '\(.*\),[^,]*'`
		case "$street_addr" in
		*,*)
			state="$city"
			city=`expr "$street_addr" : '.*,\([^,]*\)'`
			street_addr=`expr "$street_addr" : '\(.*\),[^,]*'`
			;;
		esac;;
	esac;;
esac
case "x$city" in x) city="$default_city";; esac
case "x$state" in x) state="$default_state";; esac

# map_url="http://lycos.vicinity.com/cgi-bin/webmap?Template=lycos&Style=Fancy&Alias=1&Icon=Smallcross&File=world&Address1=&Address2=${street_addr}&Address3=$city, $state"
# map_url="http://www.mapblast.com/mapblast/blast.hm?CMD=GEO&xx=1&id=9112594184707&AD2=${street_addr}&AD3=${city}, ${state}&IC=%3A%3ASmallcross&IC%3A="
# map_url="http://www.mapblast.com/mapblast/blast.hm?CMD=GEO&xx=1&AD2=${street_addr}&AD3=${city}, ${state}&IC=%3A%3ASmallcross&IC%3A="

map_url="http://www.mapblast.com/myblast/map.mb?CMD=GEO&CT=&IC=&GMI=&GAD1=&GAD2=&GAD3=&noPrefs=&remLoc=&AD4=USA&AD2_street=${street_addr}&AD3=${city} ${state}&apmenu=&apcode=&AD2=${street_addr}&req_action=crmap"

map_url=`echo "$map_url" | sed 's/%/%25/g;s/ /+/g;s/,/%2C/g'`

lynx -dump "$map_url" | sed -n 's/.*\(Lat: *-\?[.0-9]*\) *\(Lon: *-\?[.0-9]*\).*/\1\
\2/p'

addr_gps.pl

#!/usr/bin/perl -w

# addr_gps.  given an address, query web resources to convert to GPS
# latitude and longitude data.  create May 28, 2000, bsy@cs.ucsd.edu

# Copyright 2000 Bennet S. Yee (bsy@cs.ucsd.edu), all right reserved.
# This material was developed by the author and may be redistributed
# under the GNU copyright license version 2.  See http://www.gnu.org/
# for details.

# gps parser
package GP;

use HTML::Parser;
@ISA=("HTML::Parser");

my($debug) = 0;

sub new {
    my $proto = ;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new();
    bless($self, $class);
    $self->initialize();
    return $self;
}

sub initialize {
    my $self = ;

    $self->{LAT} = undef;
    $self->{LON} = undef;
}

sub _lat {
    my $self = ;
    if (@_) { $self->{LAT} =  }
    $self->{LAT};
}

sub _lon {
    my $self = ;
    if (@_) { $self->{LON} =  }
    $self->{LON};
}

sub found {
    my $self = ;
    return defined($self->{LAT}) && defined($self->{LON});
}

sub start {
    my($self,$tag,$attr,$attrseq,$origtext) = @_;
    my($i,$k);
    if ($debug > 1) {
	print "Tag($tag)";
	if (@$attrseq > 0) {
	    print ", attr( [\n";
	    foreach $k (keys %$attr) {
		print "$k => ",$$attr{$k},"\n";
	    }
	    print "] ), attrseq( [\n";
	    for ($i = 0; $i < @$attrseq; $i++) {
		print " $i: ",$$attrseq[$i],"\n";
	    }
	    print "] )";
	}
	print ", origtext($origtext)\n";
    }
    if ($tag eq 'A' || $tag eq 'a') {
	if (defined($$attr{"href"})) {
	    $k = $$attr{"href"};
	    if ($k =~ /slt=(-?[\d.]+).*sln=(-?[\d.]+)/) {
		$self->{LAT} = $1;
		$self->{LON} = $2;
	    }
	}
    }
}

sub end {
    my ($self, $tag, $origtext) = @_;
    print "EndTag($tag), origtext($origtext)\n" if $debug > 1;
}

sub text {
    my ($self, $text) = @_;
    my($country,$cc);

    print "Text($text)\n" if $debug;
    if ($text =~ /Lat:\s*(-?[\d.]+)/) {
	$self->{LAT} = $1;
    }
    if ($text =~ /Lon:\s*(-?[\d.]+)/) {
	$self->{LON} = $1;
    }
}

package main;

use LWP;

$debug = 0;
$minutes = 1;
$default_city = "San Diego";
$default_state = "CA";
$city = undef;
$state = undef;
$which_url = 0;
$in_browser = 0;

# it'd be better if we had an array of web sites, but the URL encoding
# schemes differ.

sub help {
    print STDERR "\
Usage: addr_gps [-flags] street address
 flags are: short long		meaning
            -w    --web-site    arg is web-site selection
                                  0 for maps.yahoo.com (default)
                                  1 for www.mapblash.com
            -b    --browser     display map in netscape browser
            -B    --no-browser  parse and print GPS coordinates (default)
            -m    --minutes     output in degree and minutes (default)
            -d    --degrees     output in fractional degrees
            -c    --city        city is next arg (default $default_city)
            -s    --state       state is next arg (default $default_state)
";
}

arg:
    for ($i = 0; $i < @ARGV; $i++) {
	if ($ARGV[$i] eq '-m' || $ARGV[$i] eq '--minutes') {
	    $minutes = 1;
	} elsif ($ARGV[$i] eq '-d' || $ARGV[$i] eq '--degrees') {
	    $minutes = 0;
	} elsif ($ARGV[$i] eq '-b' || $ARGV[$i] eq '--browser') {
	    $in_browser = 1;
	} elsif ($ARGV[$i] eq '-B' || $ARGV[$i] eq '--no-browser') {
	    $in_browser = 0;
	} elsif ($ARGV[$i] eq '-w' || $ARGV[$i] eq '--web-site') {
	    ++$i <= @ARGV || ($ARGV[$i] =~ /^\d+$/) || die "$ARGV[$i-1] requires numeric argument\n";
	    $which_url = $ARGV[$i];
	    if ($which_url > 1) {
		die "web-site selector out of range: 0 for maps.yahoo.com, 1 for www.mapblast.com\n";
	    }
	} elsif ($ARGV[$i] eq '-c' || $ARGV[$i] eq '--city') {
	    ++$i <= @ARGV || die "$ARGV[$i-1] requires cityname argument\n";
	    $city = $ARGV[$i];
	} elsif ($ARGV[$i] eq '-s' || $ARGV[$i] eq '--state') {
	    ++$i <= @ARGV || die "$ARGV[$i-1] requires statename argument\n";
	    $city = $ARGV[$i];
	} elsif ($ARGV[$i] eq '-h' || $ARGV[$i] eq '--help') {
	    &help();
	    exit 0;
	} elsif ($ARGV[$i] eq '--') {
	    $i++; last arg;
	} elsif ($ARGV[$i] =~ /^-.*/) {
	    die "flag $ARGV[$i] not implemented, --help for help\n";
	} else {
	    last arg;
	}
    }

if ($i < @ARGV) {
    $street_addr = join ' ', @ARGV[$i .. $#ARGV];
} else {
    @addrlines = split '\n',`xcb -p 0`;
    for ($i = 0; $i < @addrlines; $i++) {
	if ($addrlines[$i] =~ /^\.\w+A\s+(.*)/) {
	    print STDERR "match: $addrlines[$i] converting to $1" if $debug>1;
	    $addrlines[$i] = $1;
	}
    }
    $street_addr = join ', ',@addrlines;
}

if (!defined($city)) {
    if ($street_addr =~ /(.*),\s*([^,]+)/) {
	$street_addr = $1;
	$city = $2;
	if ($street_addr =~ /(.*),\s*([^,]+)/) {
	    $state = $city;
	    $city = $2;
	    $street_addr = $1;
	}
    }
}
$city = $default_city if !defined($city);
$state = $default_state if !defined($state);

print STDERR "Street address is $street_addr\n" if $debug;
print STDERR "City is $city\nState is $state\nOutput in degrees",$minutes ? " and minutes":"","\n" if $debug;

$mapblast_url="http://www.mapblast.com/myblast/map.mb?CMD=GEO&CT=&IC=&GMI=&GAD1=&GAD2=&GAD3=&noPrefs=&remLoc=&AD4=USA&AD2_street=${street_addr}&AD3=${city} ${state}&apmenu=&apcode=&AD2=${street_addr}&req_action=crmap";

$yahoo_url="http://maps.yahoo.com/py/maps.py?Pyt=Tmap&addr=${street_addr}&csz=${city} ${state}&country=us&Get%A0Map=Get+Map";

$url = $which_url ? $mapblast_url : $yahoo_url;

$url =~ s/%/%25/g;
$url =~ s/ /+/g;
$url =~ s/,/%2C/g;

if ($in_browser) {
    system("netscape -remote \"OpenURL($url,new-window)\" 2> /dev/null || netscape \"$url\"");
    exit 0;
}

print STDERR "URL is $url\n" if $debug;

$ua = LWP::UserAgent->new;
$p = GP->new;

$req = HTTP::Request->new(GET => $url);
print STDERR "fetching...\n" if $debug;
$resp = $ua->request($req);

if (!$resp->is_success) {
    die "fetch of $url failed\n";
}

print STDERR "parsing...\n" if $debug;
for $line (split '\n',$resp->content) {
    $p->parse($line);
}

die "coordinates not found\n" if !$p->found;

$lat = $p->_lat;
$lon = $p->_lon;
$ns = $lat >= 0 ? "N" : "S";
$ew = $lon >= 0 ? "E" : "W";
$lat = abs($lat);
$lon = abs($lon);
if ($minutes) {
    printf "Lat: %s %d° %.6f', Lon: %s %d° %.6f'\n",$ns,gps_deg($lat),gps_min($lat),$ew,gps_deg($lon),gps_min($lon);
} else {
    printf "Lat: %s %f, Lon: %s %f\n",$ns,$lat,$ew,$lon;
}

sub gps_deg
{
    my($d) = @_;

    int($d);
}

sub gps_min
{
    my($d) = @_;

    ($d - int($d)) * 60;
}

[ search CSE | CSE home | bsy's home page | webster i/f | MRQE | google | yahoo | hotbot | lycos | altavista | pgp key svr | spam | commerce ]
picture of bsy

bsy+cse190.s00@cs.ucsd.edu, last updated Thu Jun 22 16:06:48 PDT 2000. Copyright 2000 Bennet Yee.
email bsy.


Don't make me hand over my privacy keys!