CS2023 Assignment 7

Winter 2004

Due Wednesday, March 24, 10:30 AM, in the assignment bin on E-Level, and electronically via the "Submit your assignment" link on the CS2023 home page. This assignment will be marked out of 75 points.

Trace System

Debugging a program often involves insertion of printf statements to trace the execution of a program. Once the program is ready for distribution, these statements are either erased or surrounded with preprocessor #ifdefs. Let's say a user then reports a bug in the program, which may have been executed on a different platform on which it was written. It would be nice to get a detailed trace of the execution of the program on the user's platform, but the user doesn't have the source code so it can't be recompiled to bring back the printf statements. What is needed is a trace system which the user can switch on and produce a detailed trace of program execution.

A good trace system can tune its output to different levels of severity, such as debug, warning, and error. When the program is written, the developper inserts trace statements of the appropriate severity instead of printfs. For instance after execution of function fun(), the following statment could be inserted:

Tr_debug("after call to fun(), i = %d", i);
instead of a printf statement. The trace system would be used as well when printing an error message
Tr_error("invalid input");
Similarly, the trace system could be used to print a warning:
Tr_warn("variable x is out of range");
The developper also needs a function to set the severity level of the trace system, which prints only error messages by default. To change the severity to "warning" (which prints error and warning messages only) the following call would be made:
Tr_level(WARN);
and to print all messages the call would be: Tr_level(DEBUG); The user would normally only see error messages (if invalid input were entered, say). However, a command-line option could be used to print error and warning messages, or to print debug messages as well, or even to suppress all messages.

For this assignment you will implement a trace system module and write a short  program to test it.

Requirements

Trace Module

Write a module to implement the trace system above, using the following header file:
#ifndef TRACE_H
#define TRACE_H

enum TraceLevel{ NOTHING, ERROR, WARN, DEBUG };

void Tr_error(const char *, ...);
void Tr_warn(const char *, ...);
void Tr_debug(const char *, ...);
void Tr_level(int level);
 

#endif /* ifndef TRACE_H */

You must add comments to this header file to describe briefly what the module does in general, and for each function in particular. We haven't discussed enumerations yet (the enum statement), and may not get to them, but the concept is simple and they are covered in the textbook. One thing that does look strange is the ellipsis (...) in three of the functions. This is how C (the printf function in particular) handles variable numbers of arguments. This functionality is required, since the first three Tr_ functions can accept any number of arguments. This is covered in section 7.5 of the textbook, but the treatment there is incomplete for our purposes. We need a function like printf which can accept a variable which has been initialized by the va_start function. It's called vfprintf  (see man vfprintf, or Kernighan & Ritchie's The C Programming Language, 2nd Ed.). For instance, consider the following function, which prints an error message to stderr,

void error(char *fmt, ...)
{
    va_list args;

    va_start(args, fmt);
    fprintf(stderr, "error: ");
    vfprintf(stderr, fmt, args);
    fprintf(stderr, "\n");
    va_end(args);
}
which, when called with error("invalid input.") would  print: error: invalid input.

The Tr_error function prints the message in its argument to stderr, preceded by the string "[!]", if the severity level is either ERROR, WARN, or DEBUG. The Tr_warn function prints the message in its argument to stdout, preceded by "[W]", if the severity level is either WARN or DEBUG. The Tr_debug function prints the message in its argument to stdout, preceded by "[D]",  if the severity level is DEBUG. The Tr_level(level) function sets the severity level to level. In your module keep track of the severity level, which has a default value of ERROR, using a global variable.

Test Function

Write a program which uses the trace module, reads the severity level as a command line switch, and then calls the following function:
void showMessages(){

 Tr_debug( "debug statement" ) ;
 Tr_warn( "warn statement %d" ,1) ;
 Tr_error( "error statement" ) ;
}

The three possible options are -w for the warning level, -d for the debug level, and -n to turn off all messages, including error messages. Here is what the output of this program looks like:
$ ./test_trace
[!] error statement
$ ./test_trace -w
[W] warn statement 1
[!] error statement
$ ./test_trace -d
[D] debug statement
[W] warn statement 1
[!] error statement
$ ./test_trace -n
$
Note that since by default stderr and stdout display to the screen, [!] messages appear on the screen together with other messages.

Makefile

Write a makefile to compile the trace system module and the test program and create an executable called test_trace.

Marking Scheme

Make sure you follow the C Language Coding Standard, format your code clearly, and choose meaningful variable names: these are all worth 8 marks. The remaining marks will be assigned for correct output (the output in the above example must be able to be reproduced), implementation of the trace system module and test program as specified above.

Deliverables

A hardcopy of your assignment in the bin on E-level, which must include source code of your program and electronic submission of four files, containing the module, header file, test program, and makefile (the makefile must produce an executable called test_trace) to the "Submit your assignment" link on the CS2023 home page.
 
 
 
Eric Aubanel, Mar. 10 2004