X-Git-Url: http://dxcluster.net/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl%2FDXUtil.pm;h=d23cb92ea7daa952d57c1deacaa843aa6b329f19;hb=157f14220c0cbc875729be41a3e3a2acd18f51e1;hp=2e8a528475ba9bcc75517512d36d5dc94440b6f4;hpb=1f1ba20386876b3d2a74e5e4d77bf7119a04610b;p=spider.git diff --git a/perl/DXUtil.pm b/perl/DXUtil.pm index 2e8a5284..d23cb92e 100644 --- a/perl/DXUtil.pm +++ b/perl/DXUtil.pm @@ -3,23 +3,34 @@ # # Copyright (c) 1998 - Dirk Koopman G1TLH # -# $Id$ +# # package DXUtil; + use Date::Parse; use IO::File; +use File::Copy; use Data::Dumper; +use Time::HiRes qw(gettimeofday tv_interval); + +use strict; + +use vars qw(@month %patmap $pi $d2r $r2d @ISA @EXPORT); require Exporter; @ISA = qw(Exporter); @EXPORT = qw(atime ztime cldate cldatetime slat slong yesno promptf - parray parraypairs shellregex readfilestr writefilestr - print_all_fields cltounix unpad is_callsign - is_freq is_digits is_pctext is_pcflag insertitem deleteitem + parray parraypairs phex phash shellregex readfilestr writefilestr + filecopy ptimelist + print_all_fields cltounix unpad is_callsign is_latlong + is_qra is_freq is_digits is_pctext is_pcflag insertitem deleteitem + is_prefix dd is_ipaddr $pi $d2r $r2d localdata localdata_mv + diffms _diffms difft parraydifft is_ztime ); + @month = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); %patmap = ( '*' => '.*', @@ -28,6 +39,11 @@ require Exporter; ']' => ']' ); +$pi = 3.141592653589; +$d2r = ($pi/180); +$r2d = (180/$pi); + + # a full time for logging and other purposes sub atime { @@ -120,6 +136,22 @@ sub yesno return $n ? $main::yes : $main::no; } +# provide a data dumpered version of the object passed +sub dd +{ + my $value = shift; + my $dd = new Data::Dumper([$value]); + $dd->Indent(0); + $dd->Terse(1); + $dd->Quotekeys($] < 5.005 ? 1 : 0); + $value = $dd->Dumpxs; + $value =~ s/([\r\n\t])/sprintf("%%%02X", ord($1))/eg; + $value =~ s/^\s*\[//; + $value =~ s/\]\s*$//; + + return $value; +} + # format a prompt with its current value and return it with its privilege sub promptf { @@ -131,21 +163,37 @@ sub promptf my $q = qq{\$value = $action(\$value)}; eval $q; } elsif (ref $value) { - my $dd = new Data::Dumper([$value]); - $dd->Indent(0); - $dd->Terse(1); - $dd->Quotekeys(0); - $value = $dd->Dumpxs; + $value = dd($value); } $prompt = sprintf "%15s: %s", $prompt, $value; return ($priv, $prompt); } +# turn a hex field into printed hex +sub phex +{ + my $val = shift; + return sprintf '%X', $val; +} + +# take an arg as a hash of call=>time pairs and print it +sub ptimelist +{ + my $ref = shift; + my $out; + for (sort keys %$ref) { + $out .= "$_=" . atime($ref->{$_}) . ", "; + } + chop $out; + chop $out; + return $out; +} + # take an arg as an array list and print it sub parray { my $ref = shift; - return join(', ', @{$ref}); + return ref $ref ? join(', ', @{$ref}) : $ref; } # take the arg as an array reference and print as a list of pairs @@ -154,7 +202,7 @@ sub parraypairs my $ref = shift; my $i; my $out; - + for ($i = 0; $i < @$ref; $i += 2) { my $r1 = @$ref[$i]; my $r2 = @$ref[$i+1]; @@ -165,6 +213,28 @@ sub parraypairs return $out; } +# take the arg as a hash reference and print it out as such +sub phash +{ + my $ref = shift; + my $out; + + while (my ($k,$v) = each %$ref) { + $out .= "${k}=>$v, "; + } + chop $out; # remove last space + chop $out; # remove last comma + return $out; +} + +sub _sort_fields +{ + my $ref = shift; + my @a = split /,/, $ref->field_prompt(shift); + my @b = split /,/, $ref->field_prompt(shift); + return lc $a[1] cmp lc $b[1]; +} + # print all the fields for a record according to privilege # # The prompt record is of the format ',[,' @@ -177,18 +247,21 @@ sub print_all_fields my @out; my @fields = $ref->fields; my $field; + my $width = $self->width - 1; + $width ||= 80; - foreach $field (sort {$ref->field_prompt($a) cmp $ref->field_prompt($b)} @fields) { + foreach $field (sort {_sort_fields($ref, $a, $b)} @fields) { if (defined $ref->{$field}) { my ($priv, $ans) = promptf($ref->field_prompt($field), $ref->{$field}); my @tmp; - if (length $ans > 79) { - my ($p, $a) = split /: /, $ans; + if (length $ans > $width) { + my ($p, $a) = split /: /, $ans, 2; my $l = (length $p) + 2; - my $al = 79 - $l; + my $al = ($width - 1) - $l; + my $bit; while (length $a > $al ) { - $a =~ s/^(.{$al})//; - push @tmp, "$p: $1"; + ($bit, $a) = unpack "A$al A*", $a; + push @tmp, "$p: $bit"; $p = ' ' x ($l - 2); } push @tmp, "$p: $a" if length $a; @@ -292,6 +365,11 @@ sub writefilestr } } +sub filecopy +{ + copy(@_) or return $!; +} + # remove leading and trailing spaces from an input string sub unpad { @@ -304,13 +382,29 @@ sub unpad # check that a field only has callsign characters in it sub is_callsign { - return $_[0] =~ /^(?:[A-Z]{1,2}\d+|\d[A-Z]\d+)[A-Z0-9\/\-]+$/; + return $_[0] =~ m!^ + (?:\d?[A-Z]{1,2}\d{0,2}/)? # out of area prefix / + (?:\d?[A-Z]{1,2}\d{1,5}) # main prefix one (required) - lengthened for special calls + [A-Z]{1,5} # callsign letters (required) + (?:-(?:\d{1,2}))? # - nn possibly (eg G8BPQ-8) + (?:/[0-9A-Z]{1,7})? # / another prefix, callsign or special label (including /MM, /P as well as /EURO or /LGT) possibly + $!x; + + # longest callign allowed is 1X11/1Y11XXXXX-11/XXXXXXX } +sub is_prefix +{ + return $_[0] =~ m!^(?:[A-Z]{1,2}\d+ | \d[A-Z]{1,2}}\d+)!x # basic prefix +} + + # check that a PC protocol field is valid text sub is_pctext { - return $_[0] =~ /^[\x09\x20-\xFF]+$/; + return undef unless length $_[0]; + return undef if $_[0] =~ /[\x00-\x08\x0a-\x1f\x80-\x9f]/; + return 1; } # check that a PC prot flag is fairly valid (doesn't check the difference between 1/0 and */-) @@ -322,7 +416,7 @@ sub is_pcflag # check that a thing is a frequency sub is_freq { - return $_[0] =~ /^[\d\.]+$/; + return $_[0] =~ /^\d+(?:\.\d+)?$/; } # check that a thing is just digits @@ -331,6 +425,31 @@ sub is_digits return $_[0] =~ /^[\d]+$/; } +# does it look like a qra locator? +sub is_qra +{ + return unless length $_[0] == 4 || length $_[0] == 6; + return $_[0] =~ /^[A-Ra-r][A-Ra-r]\d\d(?:[A-Xa-x][A-Xa-x])?$/; +} + +# does it look like a valid lat/long +sub is_latlong +{ + return $_[0] =~ /^\s*\d{1,2}\s+\d{1,2}\s*[NnSs]\s+1?\d{1,2}\s+\d{1,2}\s*[EeWw]\s*$/; +} + +# is it an ip address? +sub is_ipaddr +{ + return $_[0] =~ /^\d+\.\d+\.\d+\.\d+$/ || $_[0] =~ /^[0-9a-f:,]+$/; +} + +# is it a zulu time hhmmZ +sub is_ztime +{ + return $_[0] =~ /^(?:(?:2[0-3])|(?:[01][0-9]))[0-5][0-9]Z$/; +} + # insert an item into a list if it isn't already there returns 1 if there 0 if not sub insertitem { @@ -352,3 +471,109 @@ sub deleteitem @$list = grep {$_ ne $item } @$list; return $n - @$list; } + +# find the correct local_data directory +# basically, if there is a local_data directory with this filename and it is younger than the +# equivalent one in the (system) data directory then return that name rather than the system one +sub localdata +{ + my $ifn = shift; + my $ofn = "$main::local_data/$ifn"; + my $tfn; + + if (-e "$main::local_data") { + $tfn = "$main::data/$ifn"; + if ((-e $tfn) && (-e $ofn)) { + $ofn = $tfn if -M $ofn < -M $tfn; + } else { + $ofn = $tfn if -e $tfn; + } + } + + return $ofn; +} + +# move a file or a directory from data -> local_data if isn't there already +sub localdata_mv +{ + my $ifn = shift; + if (-e "$main::data/$ifn" ) { + unless (-e "$main::local_data/$ifn") { + move("$main::data/$ifn", "$main::local_data/$ifn") or die "localdata_mv: cannot move $ifn from '$main::data' -> '$main::local_data' $!\n"; + } + } +} + +# measure the time taken for something to happen; use Time::HiRes qw(gettimeofday tv_interval); +sub _diffms +{ + my $ta = shift; + my $tb = shift || [gettimeofday]; + my $a = int($ta->[0] * 1000) + int($ta->[1] / 1000); + my $b = int($tb->[0] * 1000) + int($tb->[1] / 1000); + return $b - $a; +} + +sub diffms +{ + my $call = shift; + my $line = shift; + my $ta = shift; + my $no = shift; + my $tb = shift; + my $msecs = _diffms($ta, $tb); + + $line =~ s|\s+$||; + my $s = "subprocess stats cmd: '$line' $call ${msecs}mS"; + $s .= " $no lines" if $no; + DXDebug::dbg($s); +} + +# expects either an array reference or two times (in the correct order [start, end]) +sub difft +{ + my $b = shift; + my $adds = shift; + + my $t; + if (ref $b eq 'ARRAY') { + $t = $b->[1] - $b->[0]; + } else { + if ($adds >= $b) { + $t = $adds - $b; + $adds = shift; + } else { + $t = $main::systime - $b; + } + } + return '-(ve)' if $t < 0; + my ($d,$h,$m,$s); + my $out = ''; + $d = int $t / 86400; + $out .= sprintf ("%s${d}d", $adds?' ':'') if $d; + $t -= $d * 86400; + $h = int $t / 3600; + $out .= sprintf ("%s${h}h", $adds?' ':'') if $h; + $t -= $h * 3600; + $m = int $t / 60; + $out .= sprintf ("%s${m}m", $adds?' ':'') if $m; + if ($d == 0 && $adds || $adds == 2) { + $s = int $t % 60; + $out .= sprintf ("%s${s}s", $adds?' ':'') if $s; + $out ||= sprintf ("%s0s", $adds?' ':''); + } + return $out; +} + +# print an array ref of difft refs +sub parraydifft +{ + my $r = shift; + my $out = ''; + for (@$r) { + my $s = $_->[2] ? "($_->[2])" : ''; + $out .= sprintf "%s=%s$s, ", atime($_->[0]), difft($_->[0], $_->[1]); + } + $out =~ s/,\s*$//; + return $out; +}