home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / CLIPPER / MISC / CLM89OCT.ZIP / TRACE.CPP < prev   
Encoding:
Text File  |  1989-08-29  |  12.9 KB  |  525 lines

  1. Listing 1
  2.  
  3. #include <stdlib.h>
  4. #include <signal.h>
  5. #include "trace.h"
  6.  
  7. void
  8. loopChar()
  9. {
  10.   Trace  trace = "::loopChar";
  11.   int    c;
  12.  
  13.   trace( "entering loop" );
  14.   while ((c = getchar()) != EOF) {
  15.     putchar(c);
  16.   }
  17.   trace( "exiting loop" );
  18. }
  19.  
  20. void
  21. main( int argc, char *argv[] )
  22. {
  23.   Trace        trace = "::main";
  24.   int          c;
  25.   extern int   optind;
  26.   extern char  *optarg;
  27.  
  28.   trace( info, "The address of trace is %X", &trace );
  29.   trace( info, "The address of c is %X", &c );
  30.   trace( info, "The address of optind is %X", &optind );
  31.   while (  (c = getopt( argc, argv, "d:i" ) ) != -1 ) {
  32.     switch ( c ) {
  33.     case 'd':
  34.       trace( "changing trace mode" );
  35.       trace.setTraceMode( atoi( optarg ) );
  36.       break;
  37.     case 'i':
  38.       trace( "ignoring interrupts" );
  39.       signal( SIGINT, SIG_IGN );
  40.       break;
  41.     case '?':
  42.       trace( error, "aborting due to invalid option" );
  43.       exit( 1 );
  44.     }
  45.   }
  46.   assert( trace, optind == argc );
  47.   loopChar();
  48.   trace( "Good bye" );
  49. }
  50. end listing 1
  51.  
  52.  
  53. Listing 2
  54. /*
  55.  *  Copyright (c) 1989 Marco S. Hyman
  56.  *
  57.  *  Permission to copy all or part of this material is granted
  58.  *  provided that the original copyright notice and its date
  59.  *  appear and notice is given that copying is by permission of
  60.  *  the original author.
  61.  *
  62.  */
  63.  
  64. /*
  65. Class:    Trace
  66.  
  67. Requires:  stdio, stdarg, stdlib
  68.  
  69. Description:
  70.  
  71.   The Trace class provides trace/debugging code that always
  72.   reside in the program.  There is no way (at this time) of
  73.   compiling without the Trace/debug code.  Macro wrappers
  74.   could be designed so the class could be conditionally
  75.   included.  However, except for a few time critical places,
  76.   most programs can afford the overhead of debugging code
  77.   that can be enabled on the fly.
  78.  
  79.   Debug output is enabled when the DEBUGMODE environment
  80.   variable is defined.  The value of the DEBUGMODE variable
  81.   specifies the amount and type of debugging output required.
  82.   Debug output can also be enabled from within the program.
  83.   The expected use of this feature is to enable Trace/debug
  84.   output when a command line switch is parsed.  The
  85.   variable/switch value is a bit mask.
  86.  
  87.     3 2 1 0
  88.     | | | |________  Enable assert output when set
  89.     | | |__________  Enable trace output when set
  90.     | |____________  Enable error output when set
  91.     |______________  Enable info output when set
  92.  
  93.   All trace output is directed to stderr.
  94.  
  95.   Assert output is generated by use of the Assert macro.
  96.   Assert does NOT terminate the program when the assertion
  97.   fails.
  98.  
  99.   Trace output is generated by instantiating an object of
  100.   the trace class and using the function call operator
  101.   without a TraceType.
  102.  
  103.   Error, and info output is generated by using the function
  104.   call operator with a TraceType.
  105.  
  106.   Trace/debug output does NOT use the stream class.  C stdio
  107.   library functions are used instead.  The reason for this is
  108.   that one of the uses of this class is to develop a clone of
  109.   the version 2.0 stream class.  It also ensures that
  110.   Trace/debug output is somewhat independent of the order class
  111.   constructors are called.
  112.  
  113.   Examples of class use:
  114.  
  115.   int  Class::function( void )
  116.   {
  117.     Trace  trace = "Class::function";
  118.  
  119.     assert( trace, condition );
  120.     ...
  121.     trace( "a simple error message" );
  122.     ...
  123.     trace( error, "format", param, param );
  124.     ...
  125.     trace( info, "format", param, param );
  126.     ...
  127.   }
  128.  
  129.   When the function is entered the constructor Trace::Trace
  130.   is called which prints the passed string, usually the name
  131.   of the function, at an indent level corresponding to the
  132.   nested level of the call.  main() is at indent/nest level
  133.   0.  Nothing is printed when the function exits but the
  134.   indent level is restored to its previous value.  The error
  135.   and info operations output the passed strings (in printf
  136.   format) at the appropriate indent level.  Output from the
  137.   above example will look like the following assuming
  138.   DEBUGMODE is 15 (all trace output enabled).
  139.  
  140.     Trace Class::function
  141.       <filename>(line): assert "condition" failed
  142.       a simple error message
  143.       error: <formated error message>
  144.       info: <formatted info message>
  145.  
  146. Public Operations:
  147.  
  148.   Trace( void )
  149.     Requires:
  150.       --nothing--
  151.     Effects:
  152.       The static member traceMode is set from the value of
  153.       the environment variable DEBUGMODE.  If DEBUGMODE is
  154.       not in the environment traceMode is not modified.
  155.     Comments:
  156.       One instance of trace is defined in trace.cc to force
  157.       this constructor to be called.  When called the initial
  158.       value of the trace mode flags is retrieved from the
  159.       environment.  It is assumed (but not forced) that no
  160.       other instances of trace will be created using this
  161.       constructor.
  162.  
  163.   Trace( const char *name )
  164.     Requires:
  165.       --nothing--
  166.     Effects:
  167.       The static member indent is incremented.
  168.     Comments:
  169.       This is the standard constructor for instantiating objects
  170.       of class Trace.  The usual definition is:
  171.  
  172.         Trace trace = "string";
  173.     
  174.       where string is the name of the entity being traced.  The
  175.       string is displayed at the current indent level and then the
  176.       indent level is incremented.
  177.  
  178.   ~Trace( void )
  179.     Requires:
  180.       --nothing--
  181.     Effects:
  182.       The static member indent is decremented.
  183.  
  184.   Trace &operator () ( const char *str )
  185.     Requires:
  186.       --nothing--
  187.     Effects:
  188.       If trace output is enabled str is output to stderr. A
  189.       newline is output after str.
  190.  
  191.   Trace &operator () ( TraceMode traceMode, const char *fmt, ... )
  192.     Requires:
  193.       One parameter of the proper type for each format defined in
  194.       the passed format string.
  195.     Effects:
  196.       If the trace mode specified by traceMode is enabled vprintf
  197.       is used to format and output the passed data to stderr.  The
  198.       data is preceded by the type of output (error or info) and
  199.       terminated by a newline.
  200.  
  201.   void doAssert( const char *file, int line, const char *msg )
  202.     Requires:
  203.       --nothing--
  204.     Effects:
  205.       If assert output is enabled a message of the form
  206.         file(line): assert "msg" failed
  207.       is output to stderr.
  208.     Comments:
  209.       doAssert is designed to be called from the assert macro
  210.       defined later in this file.  The assert macro is used to
  211.       build a generic condition and make it easier to get the
  212.       file and line number of the assert call instead of the
  213.       file and line number of doAssert's definition.
  214.  
  215.   Trace &setTraceMode( unsigned int traceMode )
  216.     Requires:
  217.       --nothing--
  218.     Effects:
  219.       The data member traceMode is set from the passed value.
  220.     Comments:
  221.       This function is public to allow the default traceMode value
  222.       set from the environment to be modified under program
  223.       control, perhaps as a result of a command line switch.
  224.  
  225. Private Operations:
  226.   void indent( void )
  227.     Requires:
  228.       --nothing--
  229.     Effects:
  230.       output "level" spaces to stderr.
  231.  
  232.   int assertSet( void )
  233.     Requires:
  234.       --nothing--
  235.     Effects:
  236.       return non-zero if assert output is enabled
  237.  
  238.   int traceSet( void )
  239.     Requires:
  240.       --nothing--
  241.     Effects:
  242.       return non-zero if trace output is enabled
  243.  
  244.   int errorSet( void )
  245.     Requires:
  246.       --nothing--
  247.     Effects:
  248.       return non-zero if error output is enabled
  249.  
  250.   int infoSet( void )
  251.     Requires:
  252.       --nothing--
  253.     Effects:
  254.       return non-zero if info output is enabled
  255. */
  256.  
  257. #include <stdio.h>
  258. #include <stdarg.h>
  259.  
  260. enum TraceMode {
  261.   error,
  262.   info
  263. };
  264.  
  265. class Trace {
  266. public:
  267.          Trace( );
  268.          Trace( const char *name);
  269.          ~Trace( void );
  270.   Trace  &operator () ( const char *str );
  271.   Trace  &operator () ( TraceMode traceMode, const char *fmt, ... );
  272.   void   doAssert( const char *file, int line, const char *msg );
  273.   Trace  &setTraceMode( unsigned int traceMode );
  274. private:
  275.   void   indent( void );
  276.   int    assertSet( void );
  277.   int    traceSet( void );
  278.   int    errorSet( void );
  279.   int    infoSet( void );
  280.  
  281.   static unsigned short  level;    // indent level
  282.   static unsigned int  traceMode;  // output enable bits
  283. };
  284.  
  285. /*
  286.   The macro assert passes calls the doAssert member function only
  287.   when the condition fails.
  288. */
  289.  
  290. #define assert( trace, condition ) { \
  291.   if ( !(condition) ) { \
  292.     trace.doAssert( __FILE__, __LINE__, #condition ); \
  293.   } \
  294. }
  295.  
  296. static const int incr = 2;  // indent level increment
  297.  
  298.   // definitions of bits in DEBUGMODE
  299.  
  300. enum {
  301.   assertMask = 0x01,
  302.   traceMask = 0x02,
  303.   errorMask = 0x04,
  304.   infoMask = 0x08
  305. };
  306.  
  307. /*
  308.   Standard Trace constructor.  Output the passed string when trace
  309.   output is enabled.  Increase the indent level.
  310. */
  311.  
  312. inline
  313. Trace::Trace( const char *name )
  314. {
  315.   if ( traceSet() ) {
  316.     indent();
  317.     fputs( name, stderr );
  318.     fputc( '\n', stderr );
  319.   }
  320.   level += incr;
  321. }
  322.  
  323. /*
  324.   Decrement the indent level.
  325. */
  326.  
  327. inline
  328. Trace::~Trace( void )
  329. {
  330.   level -= incr;
  331. }
  332.  
  333. /*
  334.   Output the passed string at the current indent level when trace
  335.   output is enabled.
  336. */
  337.  
  338. inline Trace&
  339. Trace::operator () (const char *str)
  340. {
  341.   if ( traceSet() ) {
  342.     indent();
  343.     fputs( str, stderr );
  344.     fputc( '\n', stderr );
  345.   }
  346.   return *this;
  347. }
  348.  
  349. /*
  350.   Output an assert message at the current indent level when assert
  351.   output is enabled.
  352. */
  353.  
  354. inline void 
  355. Trace::doAssert( const char *file, int line, const char *msg )
  356. {
  357.   if ( assertSet() ) {
  358.     indent();
  359.     fprintf( stderr,
  360.        "%s(%d): assert \"%s\" failed\n",
  361.        file,
  362.        line,
  363.        msg );
  364.   }
  365. }
  366.  
  367. /*
  368.   Indent to "level" by writing spaces to stderr.
  369. */
  370.  
  371. inline void
  372. Trace::indent( void )
  373. {
  374.   for ( int i = level; i > 0; --i ) {
  375.     fputc( ' ', stderr );
  376.   }
  377. }
  378.  
  379. /*
  380.   Test if assert output is enabled
  381. */
  382. inline int
  383. Trace::assertSet( void )
  384. {
  385.   return traceMode & assertMask;
  386. }
  387.  
  388. /*
  389.   Test if trace output is enabled
  390. */
  391.  
  392. inline int
  393. Trace::traceSet( void )
  394. {
  395.   return traceMode & traceMask;
  396. }
  397.  
  398. /*
  399.   Test if error output is enabled
  400. */
  401.  
  402. inline int
  403. Trace::errorSet( void )
  404. {
  405.   return traceMode & errorMask;
  406. }
  407.  
  408. /*
  409.   Test if info output enabled
  410. */
  411.  
  412. inline int
  413. Trace::infoSet( void )
  414. {
  415.   return traceMode & infoMask;
  416. }
  417.  
  418. end listing 2
  419.  
  420.  
  421.  
  422. Listing 3
  423.  
  424. /*
  425.  *  Copyright (c) 1989 Marco S. Hyman
  426.  *
  427.  *  Permission to copy all or part of this material is granted
  428.  *  provided that the original copyright notice and its date
  429.  *  appear and notice is given that copying is by permission of
  430.  *  the original author.
  431.  *
  432.  */
  433.  
  434. /*
  435.   This is the implementation of the Trace debugging class.  All
  436.   member functions (save the inlines) are defined here.  See
  437.   trace.h for the class specification.
  438. */
  439.  
  440. #include "trace.h"
  441. #include <stdlib.h>
  442.  
  443. /*
  444.   The following static instantiation of Trace causes its
  445.   constructor to be called before main is entered.  This should be
  446.   the only instantiation of Trace that uses the Trace() constructor.
  447.   This constructor initializes the traceMode static variables from
  448.   the environment.  All other instantiations of the Trace object
  449.   should use the Trace( "string" ) constructor.  There is no way to
  450.   ensure that the constructor for initTraceMode is called before the
  451.   constructors for other static objects (that may use Trace!).
  452.   Many linkers will keep the sequence the files were passed to the
  453.   linker in.  If trace.o is one of the first files passed to the
  454.   linker initialization may not be a problem.
  455. */
  456.  
  457. static Trace  initTraceMode;
  458.  
  459. /*
  460.   The constructor used for initTraceMode.  Set traceMode if a
  461.   debugMode is in the environment.
  462. */
  463.  
  464. static const char *const debugMode = "DEBUGMODE";
  465.  
  466. Trace::Trace( )
  467. {
  468.   char  *modeVal = getenv( debugMode );
  469.  
  470.   if (modeVal) {
  471.     setTraceMode( atoi( modeVal ) );
  472.   }
  473. }
  474.  
  475. /*
  476.   The arrays id and mask must be initialized such that elements of the
  477.   enumeration TraceMode can be used as indexes into the arrays.
  478.   id contains the string displayed as a prefix for trace messages of
  479.   type TraceMode.  mask contains the bit mask for testing if messages
  480.   of type TraceMode are enabled.
  481.  
  482.   Both of the arrays are used by the () operator when the first
  483.   parameter is TraceMode.  The operator indents the appropriate
  484.   amount, displays the prefix from id, and then outputs the formated
  485.   string.
  486. */
  487.  
  488. static const char *const id[] = {
  489.   "error: ",
  490.   "info: "
  491. };
  492.  
  493. static int mask[] = {
  494.   errorMask,
  495.   infoMask,
  496. };
  497.  
  498. Trace &
  499. Trace::operator () ( TraceMode traceMode, const char *fmt, ... )
  500. {
  501.   if ( this->traceMode & mask[traceMode] ) {
  502.     void  *args;
  503.  
  504.     indent();
  505.     fputs( id[traceMode], stderr );
  506.     va_start( args, fmt );
  507.     vfprintf( stderr, fmt, args );
  508.     fputc( '\n', stderr );
  509.   }
  510.   return *this;
  511. }
  512.  
  513. /*
  514.   Set the static member traceMode.  Can be called by application to
  515.   override the default value set from the environment.
  516. */
  517.  
  518. Trace &
  519. Trace::setTraceMode( unsigned int traceMode )
  520. {
  521.   this->traceMode = traceMode;
  522.   return *this;
  523. }
  524. end listing 3
  525.