Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

There are nine instruction blocks here - I\'m really stuck with this and don\'t

ID: 3673438 • Letter: T

Question

There are nine instruction blocks here - I'm really stuck with this and don't know where to begin...

/ * This program implements a simple calculator application.
* It demonstrates a concepts where multiple users submitting tasks, then the
* application serially loads, computes and then generates a report.
* This is accomplished using multiple processes:
* loader (input command processor)
* ALU (arithmetic logic unit, or doing the actual calculations)
* printer (report generator)
*
* Howto compile & run:
* In the same directory, have the following file:
*    p1calc.c
*    calc.dat (or other data file)
* $ gcc p1calc.c -o p1calc.out
* $ p1calc.out calc.dat
*/

#include
#include
#include
#include
#include
#include
#include
#include
#include

// MACROS //////////////////////////////////////////////////////////////////////

#define MAX_OPS_PER_JOB 10
#define NUM_CMD_FIELDS   4

#define TRUE   1
#define FALSE 0

// Data structures /////////////////////////////////////////////////////////////

// Calculator Command Operation
typedef struct _cmd_rcd {
   char operator; // operator
   int operand1; // operand1
   int operand2; // operand2
   int result;    // result
} cmd_rcd_t;

// Global variables ////////////////////////////////////////////////////////////
// Shared Memory pointers
int         gNumCmds;                  // range: 0-done to MAX_OPS_PER_JOB
cmd_rcd_t   gCmdTbl[MAX_OPS_PER_JOB]; // all of one job's operations

// Global variables

FILE *fpIn;          // file handle pointer of input job data file
int fdOut;         // file handle pointer of output report file

// Function prototypes /////////////////////////////////////////////////////////
// [In later projects these effectively become the child processes]
int load_job(int job);              // load a user's job
void perform_arithmetic(int job);   // process the math for a job
void print_job_report(int job);     // prints a job's report

#define RPT_FILENAME "calc.rpt"

/*******************************************************************************
* main function
*    inputs (standard)
*       argc - number of command line arguments
*       argv - array of pointers to strings for each command line arguments
*    return - none
*
* This program application implements a simple calculator batch system
* to load jobs, compute and then produce a report. It reads a series of jobs
* each job being a set of commands, performing the calculator operations per
* job, and finally producing a printed output report per job.
*
* To accomplish the program it uses several function (loader, ALU and printer)
* sequentially per job.
*/
int main (int argc, char *argv[]) /* Calculator main program */
{
   char c;
   int job;
   int more_jobs; // boolean
   int done; // boolean

   setbuf(stdout, NULL); // use standard output, flush buffer

   /* read and open command file name */
   if (argc != 2) { // arg 1 = program executable_name, arg 2 - data filename
      if (argc == 1)
         printf("No data filename provided "
                "Example $ calc_semshr.out calc.dat ");
      else
         printf("No filename provided, or too many arguments "
                "Example $ calc_semshr.out calc.dat ");
      exit(EXIT_FAILURE);
   }
   else if ((fpIn = fopen(argv[1], "r")) == 0) {
      puts ("Unable to open job command file for reading. ");
      exit(EXIT_FAILURE);
   }

   printf( " "
            "Choose an output option "
            "   F or f Print the output to the file calc.rpt "
            "   S or s Print the output to the screen "
            "Press [F|f|S|s] key and then press [ENTER] key >> " );
   done = FALSE;
   while (!done) {
      c = getchar(); // blocks until information (keypress) is available
      switch(c) {
      case 'F':
      case 'f':
         if (access(RPT_FILENAME, F_OK) == 0)   // check for an old report file
            unlink(RPT_FILENAME);               // remove old report file
            /* The access() function is a low-level file IO command
             * we did not discuss in MOS Ch 1 or Lab #2. [see Ch 10] */
         // create a new report file
         /* XXX INSTRUCTION START
          * Convert the report file from using a
          *    Standard IO stdio.h file handle pointer (fp) method to using the
          *    low-level IO fcntl.h file descriptor (fd) method
          * Replace fpOut with fdOut
          * Replace fopen(), two methods possible
          * Method #1:
          *    Replace fopen() with creat()
          *       1st argument is the same
          *       2nd argument use user RWX, everyone else read-only
          *          Big Hint: (S_IRWXU|S_IRGRP|S_IROTH)
          * Method #2:
          *    Replace fopen() with open()
          *       1st argument is the same
          *       2nd argument use user create write-only
          *          Big Hint: (O_CREAT|O_WRONLY)
          *       3rd argument use user RWX, everyone else read-only
          *          Big Hint: (S_IRWXU|S_IRGRP|S_IROTH)
          *
          * Note: The old C method would use 0755 for (S_IRWXU|S_IRGRP|S_IROTH)
          *
          * Then delete this entire comment block once program is working.
          *
          * Use man or linux.die.net for more info on creat/open/fopen (or a textbook)
          * XXX INSTRUCTION END */
          fdOut = creat(RPT_FILENAME, (S_IRWXU|S_IRGRP|S_IROTH)); // open new report file
         /* XXX INSTRUCTION START
          * Convert the report file from using a
          *    Standard IO stdio.h file handle pointer (fp) method to using the
          *    low-level IO fcntl.h file descriptor (fd) method
          * Update the if condition from the fp to the fd method
          *    fp returns 0 on error (zero indicates a NULL pointer, or undefined)
          *    fd returns -1 on error (indicates failed, an error code is stored in errno)
          * Then delete this entire comment block once program is working.
          * XXX INSTRUCTION END */
         if (fpOut == 0) { // error opening new report file
            puts ("Unable to open job report file for writing. ");
            exit(EXIT_FAILURE);
         }
         done = TRUE;
         break;
      case 'S':
      case 's':
         /* XXX INSTRUCTION START
          * Convert the report file from using a
          *    Standard IO stdio.h file handle pointer (fp) method to using the
          *    low-level IO fcntl.h file descriptor (fd) method
          * Background info:
          *    Equivalents          stdio.h     fcntl.h
          *    standard device      fp *        fd
          *    inputs   keyboard    stdin       0
          *    outputs console     stdout      1
          *    errors   console     stderr      2
          * Then delete this entire comment block once program is working.
          *
          * FYI: You can change the default device in Unix/C,
          *    In Unix shell scripts use re-direction arrows   < << > >>
          *    In C programs manipulating the file descriptors and pointers,
          *    its a long discussion, but the dup() function is used to do this.
          * XXX INSTRUCTION END */
         fdout = 1;
         done = TRUE;
         break;
      default:
         printf("INVALID ENTRY - RETRY "
               "Press [F|f|S|s] key and then press [ENTER] key >> " );
         break;
      }
   }

   job = 0;
   more_jobs = TRUE;
   while (more_jobs) {
      gNumCmds = load_job(job);
      if ( gNumCmds > 0 ) {
         perform_arithmetic(job);
         print_job_report(job);
         job++;
      }
      else
         more_jobs = FALSE;
   }

   // cleanup
   fclose(fpIn);
   /* XXX INSTRUCTION START
    * Convert the report file from using a
    *    Standard IO stdio.h file handle pointer (fp) method to using the
    *    low-level IO fcntl.h file descriptor (fd) method
    * Replace fclose() with close()
    * Replace argument fpOut with fdOut
    * Then delete this entire comment block once program is working.
    *
    * Use man or linux.die.net for more info on close/fclose (or a textbook)
    * XXX INSTRUCTION END */
   fclose(fpOut);
   printf("normal exit ");
   exit(EXIT_SUCCESS);
} /* end of Calculator main */

/*******************************************************************************
* load_job function
*    inputs
*       job - job used as index for global array
*    return
*       1-10 - number of operations successfully, stored in gCmdTbl
*       0 - no more jobs to read
*
* This function will load one job's operations from an input file.
* It reads one line at a time from the file, formatted as described below.
* It loads the set of operations (a job) into an array of structures.
*
* Input file calculation command format (Postfix ie. Reverse Polish Notation):
*    three required fields separated by a space & ending with a carriage return
*    field 1 - operand 1, legal integer values, use 0 with ? terminator
*    field 2 - operand 2, legal integer values, use 0 with ? terminator
*    field 3 - one character operator, valid values are:
*       + addition
*       - subtraction
*       * multiplication
*       / division
*       % modulus
*       ? terminator
*    field 4 - EOL - end of line character
*    Examples:
*       1 2 +      for 1 + 2 = 3
*       3 6 *      for 3 * 6 = 18
*       -2 4 -     for -2 - 4 = -6
*       0 0 ?      job done
*    This is what is referred to as Reverse Polish Notation (PN)/postfix notation.
*       notation. RPN is commonly used in computer science for logic
*       representations that are stack dependent implementations, including
*       early hand-held scientific calculators and many software calculators,
*       plus stack-oriented languages like Forth, Factor & PostScript.
*       Trivia: Infix Polish Notation is used with AI language Lisp, some CS
*
* A job (terminated by a ?) can have up to MAX_OPS_PER_JOB jobs.
* Jobs in excess will result in job being split and the remainder passed to the
* next job.
*
* Note: For the purposes of not adding distracting additional code to this
*       assignment, the validation of the calculation commands input line
*       is modest, basically it assumes correct input, it will only detect
*       the simple input errors.
*/
int load_job(int job)
{
   cmd_rcd_t command;          // command record read from data file
   char eol;                  // data entry carriage return at EOL
   int num_fields;           // number of fields read
   int end_of_job = FALSE;
   int cmd;

   cmd = 0; // reset for new job to read
   do // do-while so you always attempt a read from input file at least once
   {
      // Set local command record fields to known values before read
      //    (helps to identify data file format errors)
      command = (cmd_rcd_t) {0, 0, '#', 0 };

      // Try to read a job's commands, 4 required fields per line
      // Reverse Polish Notation operator, number, number, EOL
      num_fields = fscanf(fpIn, "%d %d %c%c",
            &command.operand1, &command.operand2, &command.operator, &eol);

      if (num_fields == NUM_CMD_FIELDS) {
         switch (command.operator) {
            // accept valid operands
            case '+': // addition operand
            case '-': // subtraction operand
            case '*': // multiplication operand
            case '/': // division operand
               if (cmd < MAX_OPS_PER_JOB) {
                  gCmdTbl[cmd++] = command; // copy record
               }
               else { // max number of commands reached with no terminator
                  fprintf(stderr,
                     ">>> MAX OPERATIONS PER JOB EXCEEDED-IGNORE COMMAND "
                     " job#=%d fields-read=%d op=%c op1=%d op2=%d eol=%#04x ",
                     job, num_fields,
                     command.operator, command.operand1, command.operand2, eol);
               }
               break;

            case '?': // terminator operand
               end_of_job = TRUE;
               break;

            default:
               fprintf(stderr,
                  ">>> ILLEGAL OPERATION COMMANDED-IGNORE "
                  " job#=%d fields-read=%d op=%c op1=%d op2=%d eol=%#04x ",
                  job, num_fields,
                  command.operator, command.operand1, command.operand2, eol);
         } // end switch
      }

      else if (num_fields == EOF) { // last job read
         end_of_job = TRUE;
         if (cmd != 0) // EOF without job terminator
            printf(">>> EOF WITHOUT JOB TERMINATOR ");
      }

      else // other formatting error
         fprintf(stderr,
            ">>> IGNORE ILLEGAL COMMAND FORMAT "
            " job#=%d fields-read=%d op=%c op1=%d op2=%d eol=%#04x ",
            job, num_fields,
            command.operator, command.operand1, command.operand2, eol);

   } while (!end_of_job); // end loop */

   return(cmd);
} /* end of load_job */

/*******************************************************************************
* perform_calcuations function
*    inputs
*       job - job used as index for global array
*    return - none
*
* This function actually performs the arithmetic computations of all the
* calculation operations for a specific job.
* The operations commands have previously been placed in a global array.
*/
void perform_arithmetic(int job)
{
   char op;                // operation
   int op1, op2, answer;   // operands & result
   int cmd;                // command operation index

   for (cmd=0; cmd < gNumCmds; cmd++) {
      op = gCmdTbl[cmd].operator;
      op1 = gCmdTbl[cmd].operand1;
      op2 = gCmdTbl[cmd].operand2;
      if ((op == '/') && (op2 == 0)) { // check for divide by zero
         gCmdTbl[cmd].result = INT_MAX;
         fprintf(stderr, ">>> DIVIDE BY ZERO op1=%d op2=%d op=%c ", op1, op2, op);
      }
      else {
         switch (gCmdTbl[cmd].operator) {
            case '+': answer = op1 + op2; break;
            case '-': answer = op1 - op2; break;
            case '*': answer = op1 * op2; break;
            case '/': answer = op1 / op2; break;
            default: answer = INT_MAX;   break;
         }
         gCmdTbl[cmd].result = answer;
     }
   }

   return;
} /* end of perform_calcuations */

/*******************************************************************************
* print_memory function
*    inputs
*       job - job used as index for global array
*    return - none
*
* This function prints a report of all the calculation operations records for a
* specific job using a global array.
*/
void print_job_report(int job)
{
   int cmd; // command operation index
   /* XXX INSTRUCTION START
    * Create a character array named 'outstr' of size 100 after the prior line.
    * Then delete this entire comment block once program is working.
    *
    * Don't remember how to create an arrays, see Quickstart #5 C Arrays lecture
    *
    * Background on Strings:
    * A string is simply an array of characters terminated with a zero ''
    * The printf family of functions automatically add the ''
    *
    * FYI: There is a whole family of string manipulation functions in the
    * C String library , which for the most part I have tried to avoid
    * using in this course to keep things simple. These are efficient & capable
    * but somewhat cryptic functions heavily dependent upon pointer management,
    * and both dynamics (heap) and static (data) memory management, and are
    * frequently the source of run-time errors in the hands of newbies or lazy
    * programmers. This is why contemporary languages have IO and string
    * manipulation rules built into the language definition, not libraries.
    * Some examples include strlen (length), strcpy, strchr (string search),
    * strcat (as in Unix cat command), and many many more.
    * XXX INSTRUCTION END */

   /* XXX INSTRUCTION START
    * Background:
    * The stdio has several formated output functions
    *    printf   screen
    *    fprintf file at fp
    *    sprintf string (array) at char *
    * When using file descriptor IO read/write commands for bytes of data,
    * but you need to reformat between ASCII and binary numbers.
    *    Example: the integer number 100 decimal
    *       16-bit integer                x0064 or b0000000001100100
    *       formatted 2 ASCII character   x3535
    * Humans prefer the ASCII format, computer processors can only perform math
    * on the numeric integers. [I'm ignoring real numbers for this discussion.]
    * The easiest method is to use the string sprintf and scanf functions to
    * convert your binary information to/from strings,
    * which you can then read/write one byte at a time.
    * There is a string.h function we will use, strlen which provides the number
    * of character up to but not including the terminator ''
    * Use man or linux.die.net for more info on these functions (or a textbook)
    *
    * Convert the fprintf() statement into two statements
    * Replace fprintf with sprintf
    * Replace fp with string pointer previously declared 'outstr'
    * Other arguments remain unchanged.
    * Add a new write() function call with three arguments
    *    first - the fd
    *    second - a void cast of the string char pointer '(void *)outstr'
    *    third - the byte count, using 'strlen(outstr)'
    * Then delete this entire comment block once program is working.
    *
    * Note: No error checking on write is done to keep this simple.
    * XXX INSTRUCTION END */
   fprintf(fpOut, "REPORT FOR JOB# %d ", job);

   for (cmd=0; cmd < gNumCmds; cmd++) { // loop one command at a time
      /* The calculation operations reside in the shared memory output/print
       * buffer at the index provided. This data is then formated to the desired
       * report layout/format for printing.
       * It prints the report to the standard output device i.e the screen.
       * for a 2 -4 * command, a line of the report will look like:
       *    "INPUT> * 2 -4   CALCULATION 2*-4=-8" */
      /* XXX INSTRUCTION START
       * Repeat instruction from prior XXX step for this fprintf function.
       * Then delete this entire comment block once program is working.
       * XXX INSTRUCTION END */
      fprintf(fpOut, "Input command> %c %d %d Calculation> %d%c%d=%d ",
            gCmdTbl[cmd].operator,
            gCmdTbl[cmd].operand1,
            gCmdTbl[cmd].operand2,
            gCmdTbl[cmd].operand1,
            gCmdTbl[cmd].operator,
            gCmdTbl[cmd].operand2,
            gCmdTbl[cmd].result );
   }
   /* XXX INSTRUCTION START
    * Repeat instruction from prior XXX step in this fprintf function.
    * Then delete this entire comment block once program is working.
    * XXX INSTRUCTION END */
   fprintf(fpOut, " Number of job computations: %d ", gNumCmds );

   return;
} /* end of print_job_report */

Explanation / Answer

The program would start executing from the main function. It will call the required functions from within the main.

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

// MACROS //////////////////////////////////////////////////////////////////////

#define MAX_OPS_PER_JOB 10
#define NUM_CMD_FIELDS   4

#define TRUE   1
#define FALSE 0

// Data structures /////////////////////////////////////////////////////////////

// Calculator Command Operation
typedef struct _cmd_rcd {
   char operator; // operator
   int operand1; // operand1
   int operand2; // operand2
   int result;    // result
} cmd_rcd_t;

// Global variables ////////////////////////////////////////////////////////////
// Shared Memory pointers
int         gNumCmds;                  // range: 0-done to MAX_OPS_PER_JOB
cmd_rcd_t   gCmdTbl[MAX_OPS_PER_JOB]; // all of one job's operations

// Global variables

FILE *fpIn;          // file handle pointer of input job data file
int fdOut;         // file handle pointer of output report file

// Function prototypes /////////////////////////////////////////////////////////
// [In later projects these effectively become the child processes]
int load_job(int job);              // load a user's job
void perform_arithmetic(int job);   // process the math for a job
void print_job_report(int job);     // prints a job's report

#define RPT_FILENAME "calc.rpt"


int main (int argc, char *argv[]) /* Calculator main program */
{
   char c;
   int job;
   int more_jobs; // boolean
   int done; // boolean

   setbuf(stdout, NULL); // use standard output, flush buffer

   /* read and open command file name */
   if (argc != 2) { // arg 1 = program executable_name, arg 2 - data filename
      if (argc == 1)
         printf("No data filename provided "
                "Example $ calc_semshr.out calc.dat ");
      else
         printf("No filename provided, or too many arguments "
                "Example $ calc_semshr.out calc.dat ");
      exit(EXIT_FAILURE);
   }
   else if ((fpIn = fopen(argv[1], "r")) == 0) {
      puts ("Unable to open job command file for reading. ");
      exit(EXIT_FAILURE);
   }

   printf( " "
            "Choose an output option "
            "   F or f Print the output to the file calc.rpt "
            "   S or s Print the output to the screen "
            "Press [F|f|S|s] key and then press [ENTER] key >> " );
   done = FALSE;
   while (!done) {
      c = getchar(); // blocks until information (keypress) is available
      switch(c) {
      case 'F':
      case 'f':
         if (access(RPT_FILENAME, F_OK) == 0)   // check for an old report file
            unlink(RPT_FILENAME);               // remove old report file
          
          fdOut = creat(RPT_FILENAME, (S_IRWXU|S_IRGRP|S_IROTH)); // open new report file
        
         if (fpOut == 0) { // error opening new report file
            puts ("Unable to open job report file for writing. ");
            exit(EXIT_FAILURE);
         }
         done = TRUE;
         break;
      case 'S':
      case 's':
         fdout = 1;
         done = TRUE;
         break;
      default:
         printf("INVALID ENTRY - RETRY "
               "Press [F|f|S|s] key and then press [ENTER] key >> " );
         break;
      }
   }

   job = 0;
   more_jobs = TRUE;
   while (more_jobs) {
      gNumCmds = load_job(job);
      if ( gNumCmds > 0 ) {
         perform_arithmetic(job);
         print_job_report(job);
         job++;
      }
      else
         more_jobs = FALSE;
   }

   // cleanup
   fclose(fpIn);
   fclose(fpOut);
   printf("normal exit ");
   exit(EXIT_SUCCESS);
} /* end of Calculator main */


int load_job(int job)
{
   cmd_rcd_t command;          // command record read from data file
   char eol;                  // data entry carriage return at EOL
   int num_fields;           // number of fields read
   int end_of_job = FALSE;
   int cmd;

   cmd = 0; // reset for new job to read
   do // do-while so you always attempt a read from input file at least once
   {
      // Set local command record fields to known values before read
      //    (helps to identify data file format errors)
      command = (cmd_rcd_t) {0, 0, '#', 0 };

      // Try to read a job's commands, 4 required fields per line
      // Reverse Polish Notation operator, number, number, EOL
      num_fields = fscanf(fpIn, "%d %d %c%c",
            &command.operand1, &command.operand2, &command.operator, &eol);

      if (num_fields == NUM_CMD_FIELDS) {
         switch (command.operator) {
            // accept valid operands
            case '+': // addition operand
            case '-': // subtraction operand
            case '*': // multiplication operand
            case '/': // division operand
               if (cmd < MAX_OPS_PER_JOB) {
                  gCmdTbl[cmd++] = command; // copy record
               }
               else { // max number of commands reached with no terminator
                  fprintf(stderr,
                     ">>> MAX OPERATIONS PER JOB EXCEEDED-IGNORE COMMAND "
                     " job#=%d fields-read=%d op=%c op1=%d op2=%d eol=%#04x ",
                     job, num_fields,
                     command.operator, command.operand1, command.operand2, eol);
               }
               break;

            case '?': // terminator operand
               end_of_job = TRUE;
               break;

            default:
               fprintf(stderr,
                  ">>> ILLEGAL OPERATION COMMANDED-IGNORE "
                  " job#=%d fields-read=%d op=%c op1=%d op2=%d eol=%#04x ",
                  job, num_fields,
                  command.operator, command.operand1, command.operand2, eol);
         } // end switch
      }

      else if (num_fields == EOF) { // last job read
         end_of_job = TRUE;
         if (cmd != 0) // EOF without job terminator
            printf(">>> EOF WITHOUT JOB TERMINATOR ");
      }

      else // other formatting error
         fprintf(stderr,
            ">>> IGNORE ILLEGAL COMMAND FORMAT "
            " job#=%d fields-read=%d op=%c op1=%d op2=%d eol=%#04x ",
            job, num_fields,
            command.operator, command.operand1, command.operand2, eol);

   } while (!end_of_job); // end loop */

   return(cmd);
} /* end of load_job */


void perform_arithmetic(int job)
{
   char op;                // operation
   int op1, op2, answer;   // operands & result
   int cmd;                // command operation index

   for (cmd=0; cmd < gNumCmds; cmd++) {
      op = gCmdTbl[cmd].operator;
      op1 = gCmdTbl[cmd].operand1;
      op2 = gCmdTbl[cmd].operand2;
      if ((op == '/') && (op2 == 0)) { // check for divide by zero
         gCmdTbl[cmd].result = INT_MAX;
         fprintf(stderr, ">>> DIVIDE BY ZERO op1=%d op2=%d op=%c ", op1, op2, op);
      }
      else {
         switch (gCmdTbl[cmd].operator) {
            case '+': answer = op1 + op2; break;
            case '-': answer = op1 - op2; break;
            case '*': answer = op1 * op2; break;
            case '/': answer = op1 / op2; break;
            default: answer = INT_MAX;   break;
         }
         gCmdTbl[cmd].result = answer;
     }
   }

   return;
} /* end of perform_calcuations */


void print_job_report(int job)
{
   int cmd; // command operation index
   fprintf(fpOut, "REPORT FOR JOB# %d ", job);

   for (cmd=0; cmd < gNumCmds; cmd++) { // loop one command at a time

      fprintf(fpOut, "Input command> %c %d %d Calculation> %d%c%d=%d ",
            gCmdTbl[cmd].operator,
            gCmdTbl[cmd].operand1,
            gCmdTbl[cmd].operand2,
            gCmdTbl[cmd].operand1,
            gCmdTbl[cmd].operator,
            gCmdTbl[cmd].operand2,
            gCmdTbl[cmd].result );
   }
  
   fprintf(fpOut, " Number of job computations: %d ", gNumCmds );

   return;
}

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote