#!/usr/bin/perl # Unit conversions (weight/measure/etc) for an irssi bot. use warnings; no strict; use POSIX 'round'; use Irssi qw/signal_add/; $helpmsg = "Usage: !units [[to] ]. Examples: !units 50 miles km; !units 20C to F. With no , tries to guess based on (e.g. C will convert to F)"; # default output unit based on input unit %default_unit = ( F => 'C', C => 'F', f => 'c', c => 'f', mi => 'km', mile => 'km', km => 'mile', ft => 'meter', foot => 'm', feet => 'm', yd => 'm', yard => 'm', in => 'cm', inch => 'cm', inches => 'cm', lb => 'kg', pound => 'kg', lbs => 'kg', gal => 'l', gallon => 'l', cc => 'floz', floz => 'cc', ); # round to nearest 1/100, e.g. 1.004 is 1, 1.005 is 1.01. sub round_result { return round($_[0] * 100) / 100; } sub convert { for($_[0]) { s/°([cfk])\b/$1/i; if(/[^\s0-9a-zA-Z\/\^]/) { return "malformed request"; } s/\s+to\b//; s/fl\w*\.?\s?o[uz]\w*/floz/; my ($num, $from, $to) = (/(\d+|\.\d+|\d+\.\d+)\s*([\w\^\/]+)(?:\s+([\w+\^\/]+))?$/); return "malformed request" unless defined $num && defined $from; $to = $default_unit{$from} unless defined $to; unless(defined $to) { my $f = $from; $f =~ s/s$//; $to = $default_unit{$f}; } return "no default conversion for $from" unless defined $to; #warn "was: num $num, from $from, to $to\n"; my $realfrom = $from; my $realto = $to; my $realnum = $num; my $space = " "; if($from =~ /^([cfk])$/i) { $realfrom = uc $1; $from = "temp" . uc($1) . "($num)"; $num = ""; $space = ""; } if($to =~ /^([cfk])$/i) { $realto = uc $1; $to = "temp" . uc($1); $space = ""; } #warn "now: num $num, from $from, to $to\n"; # was using: -o'%.1f', but it doesn't do rounding, plus it # prints 1 as 1.0. chomp($result = `units -1t '$num$from' '$to' 2>&1`); if($?) { if($result =~ /conformability error/) { return "Can't convert $realfrom to $realto"; } else { return $result; } } else { $result = round_result($result); return "$realnum$space$realfrom is $result$space$realto"; } } } sub on_public_msg { my ($server, $msg, $nick, $address, $target) = @_; my $mynick = $server->{nick}; unless(length $target) { $target = $nick; $nick = $mynick; } if($target eq $mynick) { # private message... send response to sender $target = $nick; } if($msg !~ /^!units\s+(.+)/) { return; } my $input = $1; my $result = convert($input); $server->command("msg $target $result"); } signal_add("message public", "on_public_msg");