This is a(nother) long mail message.  It includes several files, marked
with FILE==================

It includes the updated list and total report program with the modifcations
to handle page breaks. It has been tested using Borland C++ v5.01.

You may need to change the directory/location of the .h file included
in busrep3.c

The changes will be discussed in the classes this week.


FILE=============================
/* busrep3.c - functions for use with awkfilt3.c to:

   PRODUCE A TYPICAL BUSINESS REPORT

      this is a typical "list and total" report

      Input is text records containing five fields as follows, a simplified
      "cash register" example:

      customer id
      invoice number
      inventory item (code or description - developer's choice)
      quantity sold
      unit price of inventory item

      a static global array (of float) is used to hold the totals

      FUNCTION begin
         intializes the array used to total the items
         formats the header line for the report
      FUNCTION process
         totals the items
         formats each detail line for the report
      FUNCTION finish
         formats the total line for the report

      ***NOTE***
         all the actual output is done by the main() function
 */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "\bpbc50\busrep3\busrep3.h"    /* function prototypes */

/*--- global data */

/* array totals[] is used to accumulate then print variouse totals         */
/* elements of the array totals are accessed using the following defines   */
static float totals[3];
#define QTY 0
#define VALUE 1
#define COUNT 2

static int page_number = 0;
static int lines_per_page = 55;
static int lines_printed = 55;

/*--- function prototypes */

int begin(char* dest, char* source);    /* user supplied function */
int process(char* dest, char* source);  /* user supplied function */
int finish(char* dest, char* source);   /* user supplied function */

int split_tokens(char* str, char* delims, int expect, char* tokens[]);

/*==================== awk-like BEGIN processing ===================*/
int begin(char* dest, char* source)     /* user supplied function */
{
  int k = 3;        /* loop control*/

  /* initialize totals to zeros */
  for (k = 0; k < 3; k++)
  {
    totals[k] = 0.0;
  }
        return 1;          /* by default write nothing to stdout at start */
}

/*====================== per-record processing =======================*/
int process(char* dest, char* source)  /* user supplied function */
{
  int word_count = 0;
  char* words[6];   /* words from input (6 is big enough ... expecting 5) */
  char temp[81];     /* used in formatting */

  /* split up input line into array*/
  word_count = split_tokens(source, " \t", 5, words);
  /* word_count should be 5 ... check and flag error if necessary */
  if (word_count != 5)
  {

          strcpy(dest, source);   /*--- by default copy source -> dest        */
    return 99;
  }

  /*--- accumulate totals */
  totals[QTY] = totals[QTY] + atof(words[3]);
  totals[VALUE] = totals[VALUE] + (atof(words[3]) * atof(words[4]) );
  totals[COUNT]++;

  /*--- format detail line for output */
  sprintf(temp, "%-5s %-5s %-20s %5.2f %7.2f %7.2f",
            words[0], words[1], words[2], atof(words[3]),
            atof(words[4]), atof(words[3]) * atof(words[4]) );
        strcpy(dest, temp);   /*--- by default copy source -> dest        */
        return 0;               /*--- by default cause dest to go to stdout */
}

/*================== awk-like END processing =======================*/
int finish(char* dest, char* source)     /* user supplied function */
{
  char temp[81];

  /*--- format data line */
  sprintf(temp,
         "Total QTY and VALUE          %9.2f       %9.2f\nITEMS=%1.0f\n\n",
                totals[QTY], totals[VALUE], totals[COUNT]);

  /*--- arrange to display/print */
  strcat(dest, "======================================================\n");
  strcat(dest, temp);
        return 0;
}

/* ============= does printing - handles page-breaks ======= */
void do_print (char* text)
{
  int err = 0;              /* holds return value of called funcs */
  char output[256] = "\0";  /* holds output text */

  /* ---- check if headings are needed ... do them if needed */
  if (lines_printed >= lines_per_page)
  {
    page_number++;
    err = do_header(output);  /* filled by function called */
    if (!err) puts(output);   /* output header */
    lines_printed = 1+ count_lines(output);
  }
  /* ---- in any case (with or without headings */
  puts(text);
  lines_printed = lines_printed + 1+ count_lines(text);
}

/* ================ counts lines in text =================== */
int count_lines(char* text)
{
  int k = 0;        /* loop control */
  int count = 0;    /* holds count of '\n' characters */

  for (k = 0; text[k] != '\0'; k++)
  {
    if (text[k] == '\n')
    {
      count++;
    }
  }
  return count;
}

/* ================ format header lines =================== */

int do_header(char* heading)
{
  /*--- format heading line */
  sprintf(heading, "\f\n\n%-5s %-5s %-20s %5s %7s %7s\n",
            "Cust#", "Inv#", "Inventory Item", "Qty", "Price", "Value");

  /*--- arrange to display/print */
  strcat(heading, "======================================================\n");
  return 0;
}

FILE=====================================

/* busrep3.h - prototypes for busrep3 */

void do_print(char* line);
int count_lines(char* line);
int do_header(char* header);

FILE===========================================

/* awkfilt3.c - awk-like filter program */
/*
        This filter program requires three functions to make it into a
        complete program. The three functions should be in ONE source
        file, sharing static global data between them if needed.  In each
        case they should set the return value to zero to tell the main
        program to output whatever is in dest, and non-zero to signal that
        nothing is to be output.  The main program is responsible for
        reading, writing and routing and should be absolutely standard.

        It is intended that the contents of dest will not be arbitrarily
        cleared ... that is to say that it MAY be used to build output
        incrementally during several function calls ... the contents only
        get written to stdout when a zero is returned to main by one of the
        three functions

        int begin(char* dest, char* src);

                This function is called ONCE prior to reading stdin. When called,
                the contents of dest are irrelevant, it is provided to enable
                data to be passed back to main. If this function returns zero (normal)
                then main() writes the contents of dest to standard output. If
                this function returns non-zero then nothing is written to stdout.
      The variable src is initialised to '\0', and it probably not useful
      but it is provided now to facilitate possible future use.

        int process(char* dest, char* source);

                This function is called once for every input record.  The input
                record is pointed to by source. Default processing is to move
                the contents of source to dest and return zero to cause the record
                to be written to stdout.  However, there is no need for the
                contents of dest to bear any relationship to source so that any output
                may be written.  To suppress the writing of output return non-zero.
                The contents of dest are NOT cleared by the standard main line program
                so that dest may be used to build output incrementally, appending data
                during several calls, then writing it based on some
                application-specific condition or trigger.


        int finish(char* dest, char* src);

                This function is called ONCE prior after eof on stdin.
                The contents of dest are irrelevant, it is provided to enable
                data to be passed back to main. If this function returns zero
                then main() writes the contents of dest to standard output. If
                this function returns non-zero then nothing is written to stdout.
      The variable src is initialised to '\0', and it probably not useful
      but it is provided now to facilitate possible future use.

*/

#define MAXLEN 256

#include <stdio.h>
#include <string.h>

int begin(char* dest, char* source);    /* user-supplied function */
int process(char *dest, char *source);  /* user-supplied function */
int finish(char* dest, char* source);   /* user-supplied function */
void do_print(char* line);              /* user-supplied function */

main(void)
{
        char input[MAXLEN] = "\0";
        char output[MAXLEN] = "\0";

        int err = 0;                   /* error flag  0 = OK */

        /*--- awk-like BEGIN processing */
        err = begin(output, input);     /* pre-file processing */
        if (!err) do_print(output);         /* write output */

        /*--- main processing */
        gets(input);                    /* get first input */
        while (!feof(stdin))
        {
                err = process(output, input);  /* process */
                if (!err) do_print(output);       /* write output */
                gets(input);                  /* get next input */
        }

        /*--- awk-like END processing */
   input[0] = '\0';              /* reset */
        err = finish(output, input);     /* post-processing */
        if (!err) do_print(output);       /* write output */

 return 0;
}

FILE=============================

ISYS290 - C PROGRAMMING
ASSIGNMENT #3
(2 weeks - 10%)
------------------------------
Write a program which produces a business report (list and total) which 
includes page control with headings repeated at the top of each new page.

You may use the filter program (main() ) and other functions presented in 
class or from your previous assignments, but you are not obliged to.  If 
you choose not to use the filter program you should ensure that the headings, 
detail processing and total printing are each handled in separate functions, 
not intermixed.

The data format for the input and the report is shown below.  You should 
test the program first using your own data.  I will provide data for the 
final test to ensure that each student's program gets the same test for the 
marking.

INPUT FORMAT

  Inventory_class       three characters used to classify inventory
  Inventory_code        five   characters
  Inventory_description one word up to 12 characters
  Item_cost             unit cost, values up to $999.99
  QOH_start             Quantity on hand at start of period, whole number 
                        5 digits
  Receipts              Items received into inventory during period, whole 
                        number, 5 digits
  Withdrawals           Items withdrawn from  inventory during period, whole 
                        number, 5 digits

The following data items are calculated and included in the report

  QOH_end               Quantity on hand at end of period, whole number 5 
                        digits
  Value                 Value of the inventory at the end of the period 
                        (QOH_end * Item_cost)

OUTPUT FORMAT

The detail lines are listed, including the calculated items in the sequence 
above.

Each column has a heading above, aligned to the left for the class, code and 
description and to the right for the numeric columns.   The heading also 
includes the page number.  The program should start a new page after printing 
55 lines.

The following data items should be totaled and the totals printed at the 
end of the job, suitably aligned under the corresponding detail columns.

QOH_start, Receipts, Withdrawals, QOH_end and Value
