addcols.awk generates a tally

Top Page
Attachments:
Message as email
+ (text/plain)
Delete this message
Reply to this message
Author: Dan&DanaMontagneseadagio@sprintmail.com
Date:  
Subject: addcols.awk generates a tally
#! /usr/bin/awk -f

# addcols.awk generates a tally.
# It reads input lines and looks at the end of each line for a real
# number preceded by an integer. The integer is optional and
# defaults to 1.

# The output line consists of:
#    whatever preceded the numbers on the input line;
#    the integer;
#    the real number and
#    the product of the two numbers. 


# Input lines that are blank, contain only white space or that have "#"
# as the first non-whitespace character are printed as they are.

# The grand total of the products of each line is displayed at the end.
#
# Any of the following are valid input lines ( without the "#" ):

# 56
# 4.78
# .78    
# 412 4.78
# 2 x 4            412     4.78
# two-by-four's                                        412        4.78


#######################################################################


# Display error message and set exit status.
function Error(a_Field, ai_Line, as_Message)
{
    printf("\"%s\" in line %d %s\n\n", a_Field, ai_Line, as_Message)
    EXIT_STATUS_ = EXIT_FAILURE_
}



# Form the first part of the output line.
function FormLineStart(ai_CurrentField,
    ls_LineStart, ls_Tmp)
{
    ls_LineStart = ""
    ls_Tmp = ""

    
    while (ai_CurrentField > 0)
    {
        ls_Tmp = $ai_CurrentField " " ls_LineStart
        ls_LineStart = ls_Tmp
        ai_CurrentField--
    }    

    
    return (ls_LineStart)
}



# Check if argument is an integer.
function IsInteger(ai_Arg,
    li_TestResults)
{
    li_TestResults = TRUE_


    if ( ai_Arg !~ /^[0-9][0-9]*$/ )
    {
        li_TestResults = FALSE_
    }


    return (li_TestResults)
}



# Check if arg is a real number.
function IsReal(af_Amt,
    li_TestResults)
{
    li_TestResults = TRUE_


    # Test for:
    # At least one digit followed by an optional decimal point and optional 
    # digits; 


    # Optional digits followed by a decimal point and digits;
    if ( af_Amt !~ /^[0-9][0-9]*\.?[0-9]*$/ && af_Amt !~ /^[0-9]*\.[0-9][0-9]*$/ )
    {
        li_TestResults = FALSE_
    }


    return (li_TestResults)
}



# Check for blank lines, lines containing only white space and lines 
# beginning with #.
function NonDataLine(as_Line,
    li_TestResults)
{
    li_TestResults = TRUE_


    if ( $0 !~ /^[ \t]*$/ && $0 !~ /^[ \t]*#/ )
    {
        li_TestResults = FALSE_
    }


    return (li_TestResults)
}



# Print a separator line.
function Separator( \
    li_Count)
{


    for ( li_Count = 0; li_Count < WIDTH_LINE_; li_Count++)
    {
        printf("%s", FILL_CHAR_)
    }


    print ""
}



BEGIN {
    # Widths of fields for printf
    WIDTH_QTY_                 = 5
    WIDTH_AMT_                 = 12
    WIDTH_PRECISION_        = 2
    WIDTH_LINE_                = 78
    WIDTH_TOTAL_             = WIDTH_AMT_ + WIDTH_QTY_ 
    WIDTH_GRANDTOTAL_         = WIDTH_TOTAL_ + 3
    WIDTH_LINESTART_         = \
        WIDTH_LINE_ - WIDTH_QTY_ - WIDTH_AMT_ - WIDTH_TOTAL_
    WIDTH_LASTLINESTART_     = WIDTH_LINE_ - WIDTH_GRANDTOTAL_


    TRUE_                    = 1
    FALSE_                    = 0


    FILL_CHAR_                = "-"


    AMT_FIELD_ERR_             = " should be a real number."


    EXIT_SUCCESS_             = 0
    EXIT_FAILURE_             = 1
    EXIT_STATUS_             = EXIT_SUCCESS_


    lf_GrandTotal = 0.00


    # Print header line.
    printf("\n%-*s%*s%*s%*s\n", WIDTH_LINESTART_, "", 
        WIDTH_QTY_, "Qty", WIDTH_AMT_, "Amt", WIDTH_TOTAL_, "Total")
    Separator()
}



# Main
{
    lf_Amt             = 0.00
    li_Qty             = 1
    lf_Total         = 0.00
    ls_LineStart     = ""
    li_CurrentField     = NF


    if ( NonDataLine($0) )
    {
        print
        next
    }


    if ( !IsReal($li_CurrentField) )
    {
        Error( $li_CurrentField, NR, AMT_FIELD_ERR_)
        exit (EXIT_STATUS_)
    }


    lf_Amt = $li_CurrentField


    if ( --li_CurrentField > 0 )
    {


        if ( IsInteger($li_CurrentField) )
        {
            li_Qty = $li_CurrentField
            li_CurrentField--
        }

        
        if ( li_CurrentField > 0 )
        {
            ls_LineStart = FormLineStart(li_CurrentField)
        }


    }


    lf_Total = li_Qty * lf_Amt
    lf_GrandTotal += lf_Total
    printf("%-*s%*d%*.*f%*.*f\n", WIDTH_LINESTART_, ls_LineStart, 
        WIDTH_QTY_, li_Qty, WIDTH_AMT_, WIDTH_PRECISION_, lf_Amt, 
        WIDTH_TOTAL_, WIDTH_PRECISION_, lf_Total)
}



END {

    if (EXIT_STATUS_ == EXIT_SUCCESS_ )
    {
        Separator()
        printf("%*s%*.*f\n\n", WIDTH_LASTLINESTART_, "Total",
            WIDTH_GRANDTOTAL_, WIDTH_PRECISION_, lf_GrandTotal)    
    }


}