#!/usr/bin/perl -w
require 5.006; # i'm using "open my $fh ..." construct
use strict;
# =================================================
# constants
# put magic constants at top, so people can easily change them
my $CHARGE_CODES_FILE = "mnta2/bmp/table/smsc/chg_indicator.hdb";
my $INPUT_TEMPLATE = "A12 A4 A20 A20
A2 A2 A2 A2
A12 A4 A24 A24";
my $SOURCE_IX = 2;
my $DEST_IX = 3;
# =================================================
# first, load up the charge database.
my %charge_codes;
{
open my $fh, $CHARGE_CODE_FILE
or die "$0: opening '$CHARGE_CODE_FILE': $!";
while ( <$fh> )
{
next if /^#/; # skip comments
s/\s+$/; # remove end of line chars
# get fields from line, clean them up.
my ( $src, $dest, $code ) = split /,/;
$src =~ s/^0+//;
$dest =~ s/^0+//;
$charge_codes{$src}{$dest} = $code;
}
}
# -------------------------------------------------
# process standard input, accumulate charges.
my %charges_against;
while ( my $input = <> )
{
# extract source and destination values
my @fields = unpack $INPUT_TEMPLATE, $input;
my $src = $fields[ $SOURCE_IX ];
my $dest = $fields[ $DEST_IX ];
# remove leading zeros
$src =~ s/^0+//;
$dest =~ s/^0+//;
# see if there are any charge codes associated with this pair.
my $code = $charge_codes{$src}{$dest};
if ( defined $code )
{
++$charges_against{$code};
}
}
# -------------------------------------------------
# output the results
foreach my $code ( sort keys %charges_against )
{
my $count = $charges_against{$code};
print "Total calls for Billing Code [$code] : $count \n";
}
# note that skip_zero is no longer necessary.
####
# the original code indicates there can never
# be more than one charge code associated with
# any given $src and $dest pair; if there are,
# we would have to use an array ref here and
# a foreach loop in the main processing.
# only one charge code:
$charge_codes{$src}{$dest} = $code;
# # for multiple charge codes:
# push @{ $charge_codes{$src}{$dest} }, $code;
####
# # if you know that there is no charge code 0 or
# # empty string, you could compress that like so:
# if ( my $code = $charge_codes{$src}{$dest} )
# {
# ++$charges_against{$code};
# }
# # if you need multiple codes per src/dest pair:
# my $charge_code_aref = $charge_codes{$src}{$dest}
# or next;
# # increment the number of charges against each code
# foreach my $code ( @$charge_code_aref )
# {
# ++$charges_against{$code};
# }
####
# construct the template in a more self-documenting way.
# this is a list of name => width values. you can add
# more info here if you like; just adjust the loops
# that pull information out of it. having all this
# information in one place means that you only have to
# change one place...
my @INPUT_COLUMN_INFO =
( unknown1 => { width => 12 },
unknown2 => { width => 4 },
source => { width => 20 },
dest => { width => 20 },
... );
# you can also use this structure to do clever things
# such as building a hash out of each input line to
# extract values by name instead of by numeric index.
# =================================================
# derived constants
my @INPUT_NAMES; # names in original order
my $INPUT_TEMPLATE; # build up an 'unpack' template
my %INPUT_POS; # map from name to index
for ( my $i = 0; $i < @INPUT_COLUMN_INFO; $i += 2 )
{
my ( $name, $info ) = @INPUT_COLUMN_INFO[$i, $i+1];
push @INPUT_NAMES, $name;
$INPUT_TEMPLATE .= "A" . $info->{width};
$INPUT_POS{$name} = @INPUT_NAMES-1;
}
# =================================================
# use during processing
while (<>)
{
# construct hash using slice
my %input;
@input{@INPUT_NAMES} = unpack $INPUT_TEMPLATE, $_;
# now access info from the hash
my $src = $input{source};
my $dest = $input{dest};
# ...
}