home *** CD-ROM | disk | FTP | other *** search
/ Amiga GigaPD 3 / Amiga_GigaPD_v3_3of3.iso / fred_fish / fish_601-700_lha / fish_663.lha / DEBUGUTILS / debug.c < prev    next >
C/C++ Source or Header  |  1993-06-02  |  14KB  |  547 lines

  1. /*                         FILE:    debug.c
  2.  *
  3.  *    Project:            DeBug Utilities
  4.  *    Version:            2.1
  5.  *
  6.  *
  7.  * This file contains:
  8.  *
  9.  *                        1.    main()
  10.  *                        2. screen_list()
  11.  *                        3. send_status()
  12.  *
  13.  * Created:            5/24/89
  14.  * Author:        Mark Porter (fog)
  15.  *
  16.  *
  17.  * $Revision: 1.1 $
  18.  * $Date: 92/05/05 19:56:10 $
  19.  * $Author: fog $
  20.  *
  21.  *
  22.  *    Copyright ⌐ 1992 if...only Amiga
  23.  *
  24.  *    Permission is granted to distribute this program's source, executable,
  25.  *    and documentation for non-commercial use only, provided the copyright
  26.  *    and header information are left intact.
  27.  *
  28.  */
  29.  
  30.  
  31. /*----------------------------------------------------------------------*/
  32. /*----------------------------------------------------------------------*
  33.  *
  34.  *
  35.  * $Log:    debug.c,v $
  36.  * Revision 1.1  92/05/05  19:56:10  fog
  37.  * Initial revision
  38.  * 
  39.  *
  40.  *
  41.  *----------------------------------------------------------------------*/
  42. /*----------------------------------------------------------------------*/
  43.  
  44.  
  45. #include <stdio.h>
  46. #include <functions.h>
  47. #include <libraries/dosextens.h>
  48. #include <exec/types.h>
  49.  
  50. #include "trace.h"
  51. #include "debug.h"
  52.  
  53.  
  54. /* The DB_function array contains strings corresponding to functions in    */
  55. /* the application which is being debugged.  If DB_Screen is db_include    */
  56. /* the list contains function names for which we want output.  If            */
  57. /* DB_Screen is db_exclude the list contains functions for which we do    */
  58. /* not want to see output.                                                                */
  59.  
  60. static char DB_Function[ DB_NUM ][ DB_BUFSIZE ];
  61.  
  62. static DB_Type DB_Screen = db_none;        /* Function screening type.        */
  63. static int        DB_Tos     = -1;            /* Top-of-Stack for DB_Function.    */
  64. static int        DB_Level     =  0;            /* Debug Level for output.            */
  65. static BOOL        DB_Check     = FALSE;        /* DB_CHECK message received.        */
  66.  
  67.  
  68. /* DB_List is used to pass a list of pointers giving tDB access to the    */
  69. /* DB_Function List entries.  This allows the user to check on which        */
  70. /* functions are currently in the list.                                            */
  71.  
  72. char  *DB_List[ DB_NUM ];
  73.  
  74. /* Version string so the AmigaDOS VERSION command will work.                */
  75.  
  76. char    *Version = "$VER: debug version 1.1 07-May-92";
  77.  
  78.  
  79. /*------------ main() ---------------
  80.  *
  81.  *
  82.  * FUNCTION:    Waits for messages to be received from other tasks and then
  83.  *                    prints values.
  84.  *
  85.  * ARGUMENTS:    Standard command line arguments.
  86.  *
  87.  * RETURNS:        Nothing.
  88.  *
  89.  * COMMENTS:    This program is a stand-alone program to be used with the
  90.  *                    Trace() function to debug tasks.  It allows a task to send
  91.  *                    output to the display even though DOS is not active (ie: the
  92.  *                    task is not a "process".
  93.  *
  94.  *                    This function will not close down on its own, it will wait
  95.  *                    until it receives a message with code = DB_QUIT.  If the
  96.  *                    program using the Trace() function does not use the DB_QUIT
  97.  *                    message I have provided an option for tDB that will close
  98.  *                    this program down properly.
  99.  *
  100.  */
  101.  
  102. main( argc,argv )
  103.     int    argc;
  104.     char *argv[];
  105. {
  106.     struct FileHandle *dos_fh;                    /* Pointer to CON window.        */
  107.     struct MsgPort        *port;                    /* debug MsgPort.                    */
  108.     Debug_Msg            *msg = NULL;            /* Pointer to message sent.    */
  109.     FILE                    *fd;                        /* Debug file if necessary.    */
  110.     long                     count;                    /* Length of string to output.*/
  111.     long                     clock;                    /* Time stamp variable.            */
  112.     BOOL                     send         = FALSE;    /* Send output to window?        */
  113.     BOOL                     write    = FALSE;    /* Write output to file?        */
  114.     BOOL                     serial   = FALSE;    /* Write to serial port?        */
  115.     BOOL                     parallel = FALSE;    /* Write to parallel port?        */
  116.  
  117.     extern char            *ctime();                /* Functions used to generate    */
  118.     extern long             time();                    /* time stamp on output.        */
  119.  
  120.     /* First open the Console window for primary debugging output.            */
  121.  
  122.     dos_fh = Open( "CON:0/0/480/100/DB Output:  v1.1",MODE_NEWFILE );
  123.  
  124.     /* If there was a command line argument, set debug level to it.        */
  125.  
  126.     DB_Level = ( argc < 2 )    ? 0 :    atoi( argv[ 1 ] );
  127.  
  128.     /* Create a MsgPort for receiving data from Trace() or tDB.                */
  129.  
  130.     if ( port = CreatePort( "Trace.DBPort",0L ))
  131.     {
  132.         Write( dos_fh,"Trace.DBPort opened successfully\n",34L );
  133.  
  134.         /* Now loop forever, receiving and processing messages.                */
  135.  
  136.         while( TRUE )
  137.         {
  138.             /* If no current message, wait till one gets here, then pull    */
  139.             /* it from the MsgPort with GetMsg().                                    */
  140.  
  141.             if (( msg = ( Debug_Msg * )GetMsg( port )) == NULL )
  142.             {
  143.                 WaitPort( port );
  144.                 msg = ( Debug_Msg * )GetMsg( port );
  145.             }
  146.  
  147.             if ( msg->DB_code == DB_QUIT )        /* Someone is telling us    */
  148.             {                                                /* to close down, so...        */
  149.                 ReplyMsg( msg );                        /* reply to sender...        */
  150.                 break;                                    /* and exit forever loop.    */
  151.             }
  152.  
  153.             send = FALSE;        /* Disable output till we know what type of    */
  154.                                     /* message has been sent.                            */
  155.  
  156.             switch( msg->DB_code )
  157.             {
  158.                 /* Message codes are fairly self-explanatory.  See other        */
  159.                 /* documentation for complete description.                        */
  160.  
  161.                 case DB_WRITE:        if (( fd = fopen( msg->DB_file,"a" )) == NULL )
  162.                                             Write( dos_fh,"File open failed\n",18L );
  163.                                         else
  164.                                         {
  165.                                             write = TRUE;
  166.                                             clock = time( NULL );
  167.                                             fprintf( fd,"\n\n\n%s\n",ctime( &clock ));
  168.                                         }
  169.                                         break;
  170.  
  171.                 case DB_ENDWRITE:    if ( write == TRUE )
  172.                                         {
  173.                                             fclose( fd );
  174.                                             write = FALSE;
  175.                                         }
  176.                                         break;
  177.  
  178.                 case DB_SER:        serial = TRUE;
  179.                                         clock  = time( NULL );
  180.                                         kprintf( "\n\n\n%s\n",ctime( &clock ));
  181.  
  182.                                         break;
  183.  
  184.                 case DB_PAR:        parallel = TRUE;
  185.                                         clock        = time( NULL );
  186.                                         dprintf( "\n\n\n%s\n",ctime( &clock ));
  187.  
  188.                                         break;
  189.  
  190.                 case DB_TOGGLE:    if ( DB_Screen == db_include )
  191.                                             DB_Screen = db_exclude;
  192.                                         else if ( DB_Screen == db_exclude )
  193.                                             DB_Screen = db_include;
  194.                                         break;
  195.  
  196.                 case DB_LEVEL:        DB_Level     = msg->DB_level;            break;
  197.                 case DB_ENDPAR:    parallel  = FALSE;                    break;
  198.                 case DB_ENDSER:    serial     = FALSE;                    break;
  199.                 case DB_CHECK:        DB_Check     = TRUE;                        break;
  200.  
  201.                 case DB_ADDFUNC:    add_functions( msg );                break;
  202.                 case DB_REMFUNC:    rem_functions( msg );                break;
  203.                 case DB_CLEAR:        clear_functions();                    break;
  204.  
  205.                 /* DB_CONTINUE value is really the one which will have been    */
  206.                 /* sent from the program being debugged.  All previous are    */
  207.                 /* from tDB for adjusting debug internal parameters.  In        */
  208.                 /* this case we allow output to be generated after having    */
  209.                 /* looked at the DB_Function List, DB_Level, and DB_Screen.    */
  210.                 /* All that code is handled within screen_list() below.        */
  211.  
  212.                 case DB_CONTINUE:    send = screen_list( msg );            break;
  213.  
  214.                 /* The default value is an error.  In this case change the    */
  215.                 /* DB_code value to inform the sender.                                */
  216.  
  217.                 default:                msg->DB_code = DB_UNKNOWN;            break;
  218.             }
  219.  
  220.             if ( send == TRUE )
  221.             {
  222.                 /* If we have determined that output should be sent, then    */
  223.                 /* we write to each of the devices indicated by the BOOL        */
  224.                 /* variables.                                                                */
  225.  
  226.                 count = ( long )strlen( msg->DB_function );
  227.                 Write( dos_fh,msg->DB_function,count );
  228.                 Write( dos_fh,": ",2L );
  229.                 Write( dos_fh,msg->DB_string,msg->DB_count );
  230.  
  231.                 if ( write == TRUE )
  232.                     fprintf( fd,"%s: %s",msg->DB_function,msg->DB_string );
  233.  
  234.                 if ( serial == TRUE )
  235.                     kprintf( "%s: %s",msg->DB_function,msg->DB_string );
  236.  
  237.                 if ( parallel == TRUE )
  238.                     dprintf( "%s: %s",msg->DB_function,msg->DB_string );
  239.             }
  240.  
  241.             ReplyMsg( msg );                /* Reply to sender.                        */
  242.             send_status( port );            /* Send status info if necessary.    */
  243.         }
  244.  
  245.         /* When we exit the loop, first make sure all messages have been    */
  246.         /* removed from the MsgPort.  If this is not done, we guarantee    */
  247.         /* a system crash very quickly.  Cleanup is done within Forbid()    */
  248.         /* Permit() calls to prevent other message from arriving while        */
  249.         /* shutdown is occuring.                                                        */
  250.  
  251.         Forbid();
  252.         {
  253.             while( msg = ( Debug_Msg * )GetMsg( port ))
  254.                 ReplyMsg( msg );
  255.  
  256.             DeletePort( port );
  257.         }
  258.         Permit();
  259.  
  260.         /* Write info in Console window, delay so user can read it, and    */
  261.         /* then close the window.                                                        */
  262.  
  263.         Write( dos_fh,"Trace DeBugging Ending!\n",25L );
  264.         Delay( 50L );
  265.         Close( dos_fh );
  266.  
  267.         if ( write == TRUE )    fclose( fd );    /* Close file if necessary.    */
  268.     }
  269.     else
  270.         fprintf( stderr,"  *** debug Error *** Could not open Trace.DBPort\n" );
  271. }
  272.  
  273.  
  274.  
  275. /*------------ add_functions() ------------
  276.  *
  277.  *
  278.  * FUNCTION:    Adds functions to screening function list.
  279.  *
  280.  * ARGUMENTS:    1.    msg:    Debug_Msg received.
  281.  *
  282.  * RETURNS:        Nothing.
  283.  *
  284.  * COMMENTS:    DB_function will have been set up by tDB to be an array
  285.  *                    of pointers to character strings which we wish to enter
  286.  *                    into the DB_Function list.
  287.  *
  288.  */
  289.  
  290. void add_functions( msg )
  291.     Debug_Msg *msg;
  292. {
  293.     char **str;
  294.     int     i;
  295.  
  296.     str = ( char ** )msg->DB_function;
  297.  
  298.     for ( i = 0; str[ i ]; i++ )
  299.     {
  300.         /* If the user attempts to add more functions to the DB_Function     */
  301.         /* list than there are spaces for, an error has resulted.  The        */
  302.         /* user is informed through the DB_OVERFLOW code returned with        */
  303.         /* the replied message.                                                            */
  304.  
  305.         if ( DB_Tos >= ( DB_NUM - 1 ))
  306.         {
  307.             msg->DB_code = DB_OVERFLOW;
  308.             break;
  309.         }
  310.  
  311.         strcpy( &DB_Function[ ++DB_Tos ][ 0 ],str[ i ] );
  312.     }
  313.  
  314.     if ( DB_Screen == db_none )    DB_Screen = db_include;
  315. }
  316.  
  317.  
  318.  
  319. /*------------ rem_functions() ------------
  320.  *
  321.  *
  322.  * FUNCTION:    Removes functions to screening function list.
  323.  *
  324.  * ARGUMENTS:    1.    msg:    Debug_Msg received.
  325.  *
  326.  * RETURNS:        Nothing.
  327.  *
  328.  * COMMENTS:    DB_function will have been set up by tDB to be an array
  329.  *                    of pointers to character strings which we wish to remove
  330.  *                    from the DB_Function list.
  331.  *
  332.  */
  333.  
  334. void rem_functions( msg )
  335.     Debug_Msg *msg;
  336. {
  337.     char **str;
  338.     int     i,j,k,last;
  339.  
  340.     str = ( char ** )msg->DB_function;
  341.  
  342.     for ( i = 0; str[ i ]; i++ )        /* Loop through the pointer array.    */
  343.     {
  344.         for ( j = last = DB_Tos; j >= 0; j-- )        /* Loop through list.    */
  345.         {
  346.             if ( !strcmp( &DB_Function[ j ][ 0 ],str[ i ] ))
  347.             {
  348.                 /* If we find a match, we want to remove this function.        */
  349.                 /* If the entry is the last in the list, clear all bytes        */
  350.                 /* within that DB_Function List entry.                                */
  351.  
  352.                 if ( j == last )
  353.                 {
  354.                     for ( k = 0; k < DB_BUFSIZE; k++ )
  355.                         DB_Function[ j ][ k ] = '\0';
  356.  
  357.                     DB_List[ j ] = NULL;
  358.                 }
  359.  
  360.                 /* Otherwise copy the last entry in DB_Function List to the    */
  361.                 /* entry we wish to remove.                                            */
  362.  
  363.                 else
  364.                 {
  365.                     strcpy( &DB_Function[ j ][ 0 ],&DB_Function[ last ][ 0 ] );
  366.                     DB_List[ last ] = NULL;
  367.                 }
  368.  
  369.                 str[ i ] = NULL;    /* Remove function pointer in list.            */
  370.                 last--;                /* Decrement last for removed entry.        */
  371.                 DB_Tos--;            /* The same for the current poition.        */
  372.             }
  373.         }
  374.     }
  375.     /* If the entire DB_Function list has been cleared, reset DB_Screen.    */
  376.  
  377.     if ( DB_Tos == -1 )        DB_Screen = db_none;
  378.  
  379.     /* Now loop through all str[ i ] pointers.  If any of them are not    */
  380.     /* NULL, then it means that a function the user wished to remove        */
  381.     /* from the DB_Function List was not there to begin with.  In this    */
  382.     /* case we send the DB_UNMATCH code back to let tDB know that an        */
  383.     /* error has occured.                                                                */
  384.  
  385.     last = i;                                /* Last element in original list is    */
  386.                                                 /* now given by i after above loop.    */
  387.     for ( i = 0; i < last; i++ )
  388.     {
  389.         if ( str[ i ] != NULL )
  390.         {
  391.             msg->DB_code = DB_UNMATCH;
  392.             break;
  393.         }
  394.     }
  395. }
  396.  
  397.  
  398.  
  399. /*------------ clear_functions() ------------
  400.  *
  401.  *
  402.  * FUNCTION:    Clears screening function list.
  403.  *
  404.  * ARGUMENTS:    None.
  405.  *
  406.  * RETURNS:        Nothing.
  407.  *
  408.  * COMMENTS:    This just loops through all bytes of DB_Function List and
  409.  *                    sets them to zero.
  410.  *
  411.  */
  412.  
  413. void clear_functions()
  414. {
  415.     int     i,j;
  416.  
  417.     for ( i = 0; i < DB_NUM; i++ )
  418.     {
  419.         for ( j = 0; j < DB_BUFSIZE; j++ )
  420.         {
  421.             DB_Function[ i ][ j ] = '\0';
  422.         }
  423.  
  424.         DB_List[ i ] = NULL;
  425.     }
  426.     DB_Tos     = -1;
  427.     DB_Screen = db_none;
  428. }
  429.  
  430.  
  431.  
  432. /*------------ screen_list() ------------
  433.  *
  434.  *
  435.  * FUNCTION:    Looks through DB_Function list to determine if output
  436.  *                    from a particular function should be enabled or disabled.
  437.  *
  438.  * ARGUMENTS:    1.    msg:    Pointer to Debug_Msg received.
  439.  *
  440.  * RETURNS:        TRUE or FALSE value determining enabled output.
  441.  *
  442.  * COMMENTS:    
  443.  *
  444.  */
  445.  
  446. BOOL screen_list( msg )
  447.     Debug_Msg *msg;
  448. {
  449.     BOOL send = FALSE;
  450.     int  i;
  451.  
  452.     /* If the functions within DB_Function List are to generate debug        */
  453.     /* output data, then return TRUE only if we find a match.                */
  454.  
  455.     if ( DB_Screen == db_include )
  456.     {
  457.         send = FALSE;
  458.  
  459.         for( i = 0; i <= DB_Tos; i++ )
  460.         {
  461.             if ( !strcmp( &DB_Function[ i ][ 0 ],msg->DB_function ))
  462.             {
  463.                 if ( msg->DB_level >= DB_Level )            send = TRUE;
  464.  
  465.                 break;
  466.             }
  467.         }
  468.     }
  469.  
  470.     /* If functions within DB_Function List are not to generate debug        */
  471.     /* output data, then return TRUE only if we do not find a match.        */
  472.  
  473.     else if ( DB_Screen == db_exclude )
  474.     {
  475.         send = ( msg->DB_level >= DB_Level ) ? TRUE : FALSE;
  476.  
  477.         for( i = 0; i <= DB_Tos; i++ )
  478.         {
  479.             if ( !strcmp( &DB_Function[ i ][ 0 ],msg->DB_function ))
  480.             {
  481.                 send = FALSE;
  482.                 break;
  483.             }
  484.         }
  485.     }
  486.  
  487.     /* Otherwise there is no specification for allowing output specific    */
  488.     /* to function names.  In this case we allow debug output only if        */
  489.     /* the debug level is < the debug level given by the message.            */
  490.  
  491.     else if ( msg->DB_level >= DB_Level )
  492.         send = TRUE;
  493.  
  494.     return( send );
  495. }
  496.  
  497.  
  498.  
  499. /*------------ send_status() ------------
  500.  *
  501.  *
  502.  * FUNCTION:    Replies to tDB if a DB_CHECK message was received.
  503.  *
  504.  * ARGUMENTS:    1.    port:    Debug reply port.
  505.  *
  506.  * RETURNS:        Nothing.
  507.  *
  508.  * COMMENTS:    This function is invoked whenever tDB has sent a DB_CHECK
  509.  *                    message to debug to ask for its internal parameters.  In
  510.  *                    this case we initialize the DB_List array to point to
  511.  *                    entries in the DB_Function List, and send a message to
  512.  *                    tDB with the information.  At this point tDB should be
  513.  *                    waiting to receive the message.
  514.  *
  515.  */
  516.  
  517. void send_status( port )
  518.     struct MsgPort *port;
  519. {
  520.     struct MsgPort *send_port;
  521.     Debug_Msg         chk;
  522.     int                 i;
  523.  
  524.     if ( DB_Check && ( send_port = FindPort( "Trace.DBReplyPort" )))
  525.     {
  526.         for ( i = 0; i <= DB_Tos; i++ )
  527.             DB_List[ i ] = &DB_Function[ i ][ 0 ];
  528.  
  529.         DB_List[ i ] = NULL;
  530.  
  531.         chk.DB_msg.mn_Node.ln_Type = ( UBYTE )NT_MESSAGE;
  532.           chk.DB_msg.mn_Node.ln_Pri  = ( BYTE )0;
  533.        chk.DB_msg.mn_Node.ln_Name = NULL;
  534.         chk.DB_msg.mn_ReplyPort    = port;
  535.        chk.DB_msg.mn_Length       = ( UWORD )sizeof( Debug_Msg );
  536.         chk.DB_code                        = DB_Screen;
  537.         chk.DB_function                = ( char * )&DB_List[ 0 ];
  538.         chk.DB_level                    = DB_Level;
  539.  
  540.         PutMsg( send_port,&chk );
  541.         WaitPort( port );
  542.         GetMsg( port );
  543.  
  544.         DB_Check = FALSE;
  545.     }
  546. }
  547.