#include<stdio.h> 
 
/* 




                 VV                   VV    EEEEEEEEEEEEEE   
                  VV                 VV     EE  
                   VV               VV      EE
                    VV             VV       EE
                     VV           VV        EE
                      VV         VV         EEEEEEEEEEEEEE
                       VV       VV          EE
                        VV     VV           EE
                         VV   VV            EE
                          VV VV             EE
                           VVV              EE
                            V               EEEEEEEEEEEEEE
                                                       
 
 
 
 
                       MODULE  : integrity.c
 
                       VERSION : v1.0
 
                       REVISED : 05 Nov 2004
 
                       AUTHOR  : Michael A. Campbell
 
 
 
 
 
 


                          FUNCTIONAL DESCRIPTION
                          ----------------------
 
               This module contains a collection of VE data structure
 
               checking routines. They are intended to act as integrity
 
               checkers for key internal datastructures. The routines

               defined here are called optionally from MAIN.C
 









*/

/* .page */

#include <curses.h>

#include "../def/common.def"

#include "../str/vestruct.str"

#include "../inc/vedbase.inc"
#include "../inc/termctl.inc"

#include "../ext/termif.ext"

static BOOL first_time     = TRUE;
static int  *stack_address = EOL;

/* .page */

void check_stack_address ()

/*
------------------------------------------------------------------------------
This routine takes the address of a local variable, which is stored on the 
stack, and compares it to the value it had on the first time through this
routine. If it is different, it writes an error out. It uses ncurses color
routines to do this in white on red.

All of this is done to keep a running check on whether the stack frame is 
balanced (i.e. all routines are being called with the correct number of 
parameters.
------------------------------------------------------------------------------
*/

begin
   char out_buf[82];
   int get_my_address;
   int *my_address;

   if ( first_time ) begin
      first_time    = FALSE;
      stack_address = &get_my_address;
   end

   else begin
      /* 2nd and later runs through. Check that stack frame hasn't moved */

      my_address = &get_my_address;

      if ( my_address != stack_address ) begin

         /* Stack frame has moved. Sound the alarm. */

         init_pair ( 3, COLOR_WHITE, COLOR_RED );
         wattron ( ve_win, COLOR_PAIR(3) );

         sprintf ( out_buf, "%s %10x %10x", "Stack frame moved: orig and curr: ",
                   stack_address, my_address );
         mv_writestr ( 0, 1, FALSE, out_buf );

         wattroff ( ve_win, COLOR_PAIR(3) );
         restore_cursor ();
      end
   end

end /* show_stack_address */

/* .page */

int curr_file_integ_ok ( err_val )
/*
------------------------------------------------------------------------------
This routine checks a number of parameters related to the current file, to
ensure that they are OK.
------------------------------------------------------------------------------
*/

int *err_val;

begin

    struct node *cnode;

    *err_val = 0;

    /* Check tail node has null fwd_link */

    cnode = curr_file.tail;
    if ( cnode->fwd_link != EOL ) then
         *err_val = 1;

    /* Check head node */

    cnode = curr_file.head;
    if ( cnode->bwd_link != (struct node *) &curr_file ) then
         *err_val = 2;

    if ( curr_file.head != curr_file.fwd_link ) then
         *err_val = 3;

    if ( *err_val == 0 ) then
         return ( TRUE );

    else
        return ( FALSE );

end /* curr_file_integ_ok */

/* .page */

int curr_screen_integ_ok ( err_val )
/*
------------------------------------------------------------------------------
This routine checks a number of parameters related to the current screen, to
ensure that they are OK.
------------------------------------------------------------------------------
*/

int *err_val;

begin

    int i;
    struct node *cnode;

    int tail_present, curr_line_present, bottom_present;

    tail_present      = FALSE;
    curr_line_present = FALSE;
    bottom_present    = FALSE;

    *err_val = 0;

    /* Check that bottom within correct number of lines of top, that    */
    /* current line is within top and bottom, and that if bottom is     */
    /* correct number of lines away from top that bottom is present.    */

    cnode = curr_screen.top;

    for ( i = 0; i < lines - 2; i++ ) begin

        if ( cnode == curr_file.tail ) then
            tail_present = TRUE;

        if ( cnode == curr_line ) then
            curr_line_present = TRUE;
            
        if ( cnode == curr_screen.bottom ) then
            bottom_present = TRUE;

        cnode = cnode->fwd_link;

        if ( cnode == EOL ) then
            break;

    end /* for */

    /* Analyze the results */

    if ( !curr_line_present ) then
        *err_val = 1;

    if ( !bottom_present ) then
        *err_val = 2;

    if ( i < lines - 2 && !tail_present ) then
        *err_val = 3;

    /* Return results */

    if ( *err_val == 0 ) then
        return ( TRUE );

    else
        return ( FALSE );

end /* curr_screen_integ_ok */

/* .page */

int list_integ_ok ( list, err_val )
/*
------------------------------------------------------------------------------
This routine checks a number of parameters related to the supplied list, to
ensure that they are OK.
------------------------------------------------------------------------------
*/

struct file_ctl *list;
int *err_val;

begin
    struct node *cnode, *pnode, *nnode;
    int top_present, bottom_present;
    int num_nodes = 0;

    *err_val = 0;
    top_present = bottom_present = FALSE;

    /* Check that the head node and the fwd link of the file descriptor */
    /* agree with each other                                            */

    cnode = list->head;
    if ( list->fwd_link != cnode ) then
       *err_val = 1;

    /* Check that the number of nodes is > 0 */

    if ( list->nodes < 0 ) then
       *err_val = 2;

    /* Traverse the list, checking each node */

    while ( cnode != EOL && *err_val == 0 ) begin

        num_nodes += 1;

        /* Check forward node.  It should point back, except for end of file */

        nnode = cnode->fwd_link;
        if ( nnode != EOL )
           if ( nnode->bwd_link != cnode ) then
               *err_val = 3;

        /* Check backward node.  It should point forward to us, even for     */
        /* the head of the file.                                             */

        pnode = cnode->bwd_link;
        if ( pnode->fwd_link != cnode ) then
            *err_val = 4;

        /* Check that tail pointer and last line agree with each other      */

        if ( cnode->fwd_link == EOL && curr_file.tail != cnode ) then
            *err_val = 5;

        /* Check whether or not curr_screen variables are present           */

        if ( cnode == curr_screen.top ) then
             top_present = TRUE;

        if ( cnode == curr_screen.bottom ) then
             bottom_present = TRUE;

        /* Advance to next node */

        cnode = cnode->fwd_link;

    end /* while */

    /* Look at results */

    if ( *err_val == 0 ) begin

        if ( !top_present ) then
            *err_val = 6;

        if ( !bottom_present ) then
            *err_val = 7;

        if ( !top_present && !bottom_present ) then
            *err_val = 8;
    end

    if ( list->nodes != num_nodes ) then
       *err_val = 9;

    /* Return results */

    if ( *err_val == 0 ) then
        return ( TRUE );

    else
        return ( FALSE );

end /* list_integ_ok */

/* .page */

void write_error ( string, value )
/*
------------------------------------------------------------------------------
This routine writes an error code onto the VE divider line, using white text
on red background.
------------------------------------------------------------------------------
*/

char *string;
int value;

begin
    char out_buf [82];

    init_pair ( 3, COLOR_WHITE, COLOR_RED );
    wattron ( ve_win, COLOR_PAIR(3) );

    sprintf ( out_buf, "%s %d", string, value );
    fast_mv_writestr ( 0, 0, TRUE, out_buf );

    wattroff ( ve_win, COLOR_PAIR(3) );

end /* write_error */

/* .page */

void ve_integrity_check ()

begin

    int err_val;

    /* This is the mainline integrity checker. */

    if ( !curr_file_integ_ok(&err_val) ) then
        write_error ( "Current File Integrity Fail", err_val );

    if ( !curr_screen_integ_ok(&err_val) ) then
        write_error ( "Current Screen Integrity Fail", err_val );

    if ( !list_integ_ok(&curr_file, &err_val) ) then
        write_error ( "List Integrity Fail", err_val );

end /* ve_integrity_check */

