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.
#ifndef TRACE_HYou 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,
#define TRACE_Henum 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 */
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.
void showMessages(){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:Tr_debug( "debug statement" ) ;
Tr_warn( "warn statement %d" ,1) ;
Tr_error( "error statement" ) ;
}
$ ./test_traceNote that since by default stderr and stdout display to the screen, [!] messages appear on the screen together with other messages.
[!] 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
$