#!/usr/bin/perl use strict; use warnings; use File::Temp qw/tempfile/; use POSIX qw/strftime/; use Time::Local; my $RIG_URL_PREFIX = 'http://metobs.ssec.wisc.edu/pub/cache/aoss/tower/ascii'; # MAIN ------------------------------------------------------------------------- my ($year, $month, $day) = process_arguments() or exit(1); my $filename = fetch_weather_data($year, $month, $day) or exit(1); my $weather_ref = analyze_rig_data($filename) or exit(1); save_data("temps-$year-$month-$day.txt", $weather_ref) or exit(1); exit 0; # SUBROUTINES ------------------------------------------------------------------ # process_arguments() => (year, month, day) # # Examines the command-line arguments for a valid date string, and if found, # returns its year, month, and day components. Returns undef upon failure. sub process_arguments { unless ((scalar(@ARGV) == 1) and ($ARGV[0] =~ /^(\d{4})-(\d\d)-(\d\d)$/)) { print "Run with a single date argument, YYYY-MM-DD\n"; return; } return ($1, $2, $3); } # fetch_weather_data # # Downloads the RIG data file for the given date, if the downloaded file does # not already exist. Returns the name of the download file upon success (even # if the downloaded file exists), or undef upon failure. sub fetch_weather_data { my ($year, $month, $day) = @_; my $rig_filename = "rig_tower.$year-$month-$day.ascii"; my $local_filename = "rig-$year-$month-$day.txt"; if (-f $local_filename) { print "Already downloaded data for $year-$month-$day\n"; } else { my $url = "$RIG_URL_PREFIX/$year/$month/$rig_filename"; system('curl', '--fail', '--silent', '--output', $local_filename, $url); unless ($? == 0) { print "Failed to download '$url': $!\n"; return; } } return $local_filename; } # analyze_rig_data(filename) => reference to hash # # Reads and analyzes RIG data from the given filename. Returns a reference to a # hash; see homework description for full details. Returns undef upon failure. sub analyze_rig_data { my $filename = shift; my $rig; unless (open($rig, '<', $filename)) { print "Could not open '$filename': $!\n"; return; } my %weather; while (<$rig>) { my ($timestamp, $temperature) = extract_weather_data($_); my $hourstamp = timelocal(0, 0, (localtime($timestamp))[2..5]); if (exists $weather{$hourstamp}) { $weather{$hourstamp}{'min'} = $temperature if $temperature < $weather{$hourstamp}{'min'}; $weather{$hourstamp}{'max'} = $temperature if $temperature > $weather{$hourstamp}{'max'}; } else { $weather{$hourstamp} = { 'min' => $temperature, 'max' => $temperature }; } } close($rig); return \%weather; } # extract_weather_data(line) => (timestamp, temperature) # # Analyzes a single line of AO&SS RIG data, extracts the time and temperature, # converts both values to standardized units, and returns them. Remember that # the time in the RIG data is for UTC, not local time. Also, the temperatures # in the file are in Celsius, but the temperature part of the return value from # this function should be in Fahrenheit. sub extract_weather_data { my $line = shift; # WRITE THIS SUBROUTINE! return ($timestamp, $temperature_f); } # c2f(temperature_celsius) => temperature_fahrenheit # # Converts the given temperature from Celsius to Fahrenheit. The argument is # assumed to be valid, so no error checking is needed. Returns the converted # temperature. sub c2f { # WRITE THIS SUBROUTINE! } # save_data(filename, reference to hash) => success? # # Builds up a single string of formatted weather data from the given hash, then # uses write_file() to save the string to the given filename. Does NOT replace # an existing file at the given filename. The reference refers to a hash; see # homework description for full details. # # For each timestamp key, save one line of data: # # DATE HOUR MIN TEMP MAX TEMP # # The date is in YYYY-MM-DD format, the hour is in 24-hour format (i.e., 0-23), # and the temperatures have 3 digits of decimal precision. # # Returns true on success, false otherwise. sub save_data { my ($filename, $weather_ref) = @_; # WRITE THIS SUBROUTINE! } # write_file(filename, contents) => status # # Writes the given string contents to the given file safely. Returns true upon # success or false otherwise. sub write_file { my ($filename, $contents) = @_; # write new file my ($output_fh, $new_filename) = tempfile(DIR => '.', UNLINK => 0); # croak() on error print $output_fh $contents or return; close($output_fh) or return; # backup old copy and save new if (-e $filename) { rename($filename, "$filename.BAK") or return; } rename($new_filename, $filename) or return; chmod 0644, $filename or return; return 1; }