/************************************************************************/
/* EICK SOFTWARE MODULE HEADER  *****************************************/
/************************************************************************/
/*   (c) Copyright Eick Systems, Inc.,					*/
/* 	 1989  All Rights Reserved 					*/
/*									*/
/* MODULE NAME : qc_prg.c 						*/
/* PRODUCT(S)  : 							*/
/*									*/
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE :				*/
/*									*/
/* MODIFICATION LOG :							*/
/*  Date     Who   Rev			Comments			*/
/* --------  ---  ------   -------------------------------------------	*/
/* 06/06/89  MDE   1.00    New						*/
/************************************************************************/


/************************************************************************/
/* INCLUDE FILES                                                    	*/
/************************************************************************/

#include <obdefs.h>
#include <gemdefs.h>
#include <osbind.h>
#include <stdio.h>
#include <fcntl.h>
#include <strings.h>
#include <ctype.h>
#include "gemutil.h"

/************************************************************************/
/* file names								*/

#define MAX_FILE_NAME	200

char file1_name[MAX_FILE_NAME+1];
char file2_name[MAX_FILE_NAME+1];

/************************************************************************/
/*			main						*/
/************************************************************************/

main ()
  {
char *fname;
int text;
int fptr1;
int fptr2;

  gemstart (); 	 		/* Initialize GEM use 		     	*/
  while (1)
    {
    fname = get_fname ("*.*");	/* get pointer to file #1 name		*/ 
    if (fname)			/* if user selects a file		*/
      {
      strcpy (file1_name,fname);	/* save the name		*/
      fptr1 = open (fname,O_RDONLY|O_BINARY);
      if (fptr1 != -1)		/* if OK				*/
        {
        fname = get_fname ("*.*");
        if (fname)		/* if user selects a second file	*/
          {
          strcpy (file2_name,fname);	/* save the name		*/
          fptr2 = open (fname,O_RDONLY|O_BINARY);
          if (fptr2 != -1)		/* if both files open OK	*/
            {
            comp_files (fptr1,fptr2);	/* compare the files		*/
            close (fptr1);		
            close (fptr2);
            }
          else				/* could not open file 2 	*/
	    {
	    close (fptr1);
            form_alert (1,"[0][FILE OPEN PROBLEM][OK]");
	    }
          }
        else				/* not valid second file	*/
          close (fptr1);
	}                                           
      else				/* could not open file 1 */
        form_alert (1,"[0][FILE OPEN PROBLEM][OK]");
      }
    if (form_alert (1,"[0][COMPARE ANOTHER?][YES|NO]") != 1)
      break;
    }
  appl_exit();			       /* time to quit			*/
  }

/************************************************************************/
/*			comp_files					*/
/* This fun. does the actual compare, and flags differences if found	*/
/************************************************************************/

#define COMP_BUF_SIZE		0X2000

int comp_files (fptr1,fptr2)
int fptr1;
int fptr2;
  {
register unsigned char *ptr1;	/* ptr1 = A5 				*/
register unsigned char *ptr2;	/* ptr2 = A4				*/
register int count;		/* count = D7				*/

unsigned char *buf1;
unsigned char *buf2;
int count2;
int exit;
register int err;
long file_pos;

/* malloc a pair of 32k buffers, plus 4 extra bytes to be sure!		*/
  buf1 = (unsigned char *) calloc (1,COMP_BUF_SIZE+4);
  buf2 = (unsigned char *) calloc (1,COMP_BUF_SIZE+4);
  if (!buf1 || !buf2)
    return (1);


  file_pos = 0;				/* current file opsition	*/
  exit = 0;
  while (!exit)
    {					/* read both files		*/
    count = read (fptr1,buf1,COMP_BUF_SIZE);    
    count2 = read (fptr2,buf2,COMP_BUF_SIZE);    

    if (count != count2)
      {
      form_alert (0,"[0][FILE SIZE MISMATCH][OK]");
      break; 
      }
    else				/* counts are equal		*/
      {
      if (!count)			/* if both files empty, done	*/
        {
        form_alert (0,"[0][FILES COMPARE OK!][OK]");
        break;
        }
      else				/* we have two blks to compare	*/
        { 
/* Do long word compares using in-line assembly, to make it fast!	*/

        ptr1 = buf1;			/* ptr1 = A5 			*/
        ptr2 = buf2;			/* ptr2 = A4			*/
        asm 
          {
          move #0,err			; start with no error
          lsr.w    #2,D7		; divide count by 4		
          subq.w   #1,D7		; count goes -1		          

        lp:				; compare loop
          cmpm.l  (A5)+,(A4)+		; compare 4 bytes
          dbne    D7, lp		; if equal & still count, loop
          beq ok			; if was equal, branch
          move #1,err			; set error code
	ok:
          }

        file_pos += ptr1-buf1;		/* update file position		*/
        if (err)			/* if error detected		*/
          {
          disp_diff (fptr1,fptr2,file_pos-1); /* show differences	*/
          exit = 1;
          break;
          }
	}
      }      
    }
  free (buf2);
  free (buf1);				/* free the data buffers	*/
  }

/************************************************************************/
/*			disp_diff					*/
/************************************************************************/

#define NO_LIST 	1
#define HEX_LIST	2

#define BUF_SIZE		96
#define BYTES_PER_LINE		16

#define FILE1_START  	 1
#define FILE2_START      11

char hex[BYTES_PER_LINE*3+2];
char ascii[BYTES_PER_LINE+2];
char alert_str[100];

disp_diff (fptr1,fptr2,file_pos)
int fptr1;
int fptr2;
long file_pos;
  {
int choice;
long pos;
char buf1[BUF_SIZE];
char buf2[BUF_SIZE];
int count1;
int count2;
char addr[10];
int i,j;
int lnum;
int h;
int a;
int d;

  sprintf (alert_str,
    "[0][FILE MISMATCH AT APPROX %lx (HEX)][OK|SHOW ME]",
    file_pos);
  choice = form_alert (1,alert_str);
  if (choice != NO_LIST)
    {
    				/* no fancy controls			*/
    open_window (0," FILE COMPARE  ",xdesk,ydesk,wdesk,hdesk);
    hide_mouse ();
    vsf_color(vw_handle,0); 	/* set fill color = background		*/
    fill_box (xwork,ywork,wwork,hwork);
    pos = file_pos - BUF_SIZE / 2;
    if (pos < 0)
      pos = 0;
    pos &= 0xFFFF0;		/* start list on even 16 byte boundary	*/

    lseek (fptr1,pos,0);
    lseek (fptr2,pos,0);
    count1 = read (fptr1,buf1,BUF_SIZE);    
    count2 = read (fptr2,buf2,BUF_SIZE);    

    str_print (file1_name,0,FILE1_START);
    str_print (file2_name,0,FILE2_START);
    for (lnum = 2,i = 0; i < count1;)
      {
      sprintf (addr,"%05lX    ",pos);
      str_print (addr,0,lnum+FILE1_START);
      str_print (addr,0,lnum+FILE2_START);
      for (j = 0; j < BYTES_PER_LINE; ++j,++i)
        {				/* first file 1			*/
        if (buf1[i] != buf2[i])
          vst_effects (vw_handle,0);	/* make normal			*/
        else
          vst_effects (vw_handle,2);	/* make light			*/
          
        sprintf (hex,"%02x ",buf1[i] & 0xff);
        if (isalnum (buf1[i]) || ispunct (buf1[i]))
          sprintf (ascii,"%c",buf1[i] & 0xff);
        else
          sprintf (ascii,"%c",'.');
        str_print (hex,8+(3*j),lnum+FILE1_START);
        str_print (ascii,62+j,lnum+FILE1_START);

        sprintf (hex,"%02x ",buf2[i] & 0xff);
        if (isalnum (buf2[i]) || ispunct (buf2[i]))
          sprintf (ascii,"%c",buf2[i] & 0xff);
        else
          sprintf (ascii,"%c",'.');
        str_print (hex,8+(3*j),lnum+FILE2_START);
        str_print (ascii,62+j,lnum+FILE2_START);
        }
      vst_effects (vw_handle,0);		/* make normal			*/
      lnum++;
      pos += BYTES_PER_LINE;
      }
    show_mouse ();
    str_print ("Hit A Key To Continue - ",1,21);
    wait_key ();
    wind_close(wi_handle);
    wind_delete(wi_handle);
    wi_handle = NO_WINDOW;
    }
  }
 
/************************************************************************/
/************************************************************************/
/* GEM UTILITY FUNCTIONS						*/
/************************************************************************/
/************************************************************************/
/* GLOBAL VARIABLES                                                     */
/************************************************************************/
/* GEM related variables                                                                                */

int      gl_apid;

int     menu_id ;       /* our menu id (accessory only)         	*/

			/* resolution flags				*/
int mono_flag;
int med_flag;
int low_flag;

/* These variables are set when the graf_handle fun  is called  	*/
/* which is done first thing.                                           */
int     gl_hchar;       /* height of a character in pixels      	*/              
int     gl_wchar;       /* width                                	*/
int     gl_wbox;        /* width of a character sized box       	*/
int     gl_hbox;        /* height                        		*/
int     gr_handle;      /* physical workstation handle          	*/

/* The virtual workstation handle is ret'd by v_opnvwk, given   	*/
/* the physical handle (gr_handle).                                     */
int vw_handle;          /* virtual workstation handle           	*/

/* The parameters below are set when the window is opened       	*/
int wi_handle;      	/* window handle                        	*/
int xdesk;              /* desktop size, location parameters    	*/
int ydesk;              /* in pixels.                         		*/
int hdesk;
int wdesk;

/* Current window size and location parameters, updated when    	*/
/* the window in manipulated.                                           */
int xwork;
int ywork;
int hwork;
int wwork;

/* These variables are used to hold the 'old' window size, for  	*/
/* when the window is 'fulled', so that it can be restored.     	*/
int     xold;
int yold;
int hold;
int wold;

/*  This is the handle of the currently topped window           	*/
int     top_window;     /* handle of topped window              	*/

/* These parameters are used to handle data returned from the   	*/
/* event handler - event_multi.                                 	*/
int     msgbuff[17];	/* event message buffer                 	*/
int     keycode;        /* keycode returned by event-keyboard   	*/
int     mx,my;          /* mouse x and y pos.               		*/
int     butdown;        /* button state tested for, UP/DOWN     	*/
int     ret;            /* dummy return variable   			*/

/* General state variables.                                   		*/
int     m_hidden;       /* current state of cursor           		*/
int     w_fulled;       /* current state of window              	*/

/* VDI function in/out arrays                              		*/
/* These are not generally used directly, but are used by the   	*/
/* GEM binding routines.                                               	*/
int     contrl[12];     /* function control parameters          	*/
int     intin[128];     /* integer input array                  	*/
int     ptsin[128];     /* input coordinate array               	*/
int     intout[128];    /* integer output array                 	*/
int     ptsout[128];    /* output coordinate array              	*/

/* The pointer below will be set to point to a 32k buffer for   	*/
/* storing screen image before puting up forms, etc.            	*/
char *scr_buf;          /* screen sized buffer                  	*/

/* this flag is used internally only					*/
int accessory = 0;
/************************************************************************/
/*  GEM STARTUP AND EXIT ROUTINES.                              	*/
/************************************************************************/

gemstart ()
  {
int txt_attrib[10];
int std_hchar;

  scr_buf = malloc (0x7FFF); 	/* allocate screen buffer          	*/
  appl_init();
  gr_handle = graf_handle(&gl_wchar,&gl_hchar,&gl_wbox,&gl_hbox);
  wind_get(0, WF_WORKXYWH, &xdesk, &ydesk, &wdesk, &hdesk);
  wi_handle=NO_WINDOW;
  m_hidden = FALSE;
  w_fulled = FALSE;
  butdown = TRUE;
  open_vwork ();
				/* get correct values for gl_box	*/
  vqt_attributes (vw_handle,txt_attrib);
  std_hchar = txt_attrib[7];
  vst_height(vw_handle,std_hchar,&gl_wchar,&gl_hchar,&gl_wbox,&gl_hbox);

  }


gemexit ()
  {
  wind_close(wi_handle);
  graf_shrinkbox(xwork+wwork/2,ywork+hwork/2,gl_wbox,gl_hbox,
                                            xwork,ywork,wwork,hwork);
  wind_delete(wi_handle);
  v_clsvwk(vw_handle);
 
  appl_exit();
  }

/************************************************************************/
/* open and initialize virtual workstation                      	*/
/* This function must be called after 'gr_handle' has been      	*/
/* initialized, and before using any screen functions           	*/
/* Returns the workstation handle                               	*/
/************************************************************************/

/* This array is written with workstation parameters after   		*/
/* v_opnwk is called.                                                   */

int work_out[57];

int open_vwork()
  {
int work_in[11];       /* workstation init parameter array   	   	*/
int i;
                               /* NOTE : These may not have effect     	*/
  work_in[0] = 1;      /* device ID number                             	*/
  work_in[1] = 1;      /* linetype                                     	*/
  work_in[2] = 1;      /* polyline color index                         	*/
  work_in[3] = 1;      /* marker type                                  	*/
  work_in[4] = 1;      /* polymarker color index                       	*/
  work_in[5] = 1;      /* text face                                    	*/
  work_in[6] = 1;      /* text color index                             	*/
  work_in[7] = 1;      /* fill interior style                          	*/
  work_in[8] = 1;      /* fill style index                             	*/
  work_in[9] = 1;      /* fill color index                             	*/
  work_in[10] = 2;     /* Normalized to Raster flag  	           	*/

  vw_handle=gr_handle;          /* vw_handle is in and out param       	*/
  v_opnvwk(work_in,&vw_handle,work_out);

  if (NUM_COLORS == 2)		/* determine resolution			*/
    mono_flag = 1;
  if (NUM_COLORS == 4)
    med_flag = 1;
  if (NUM_COLORS == 16)
    low_flag = 1;

  return (vw_handle);
  }


/************************************************************************/
/* open window                                                  	*/
/* This function opens a window, returns the window handle.     	*/
/* Input params select window type, title, window size & locat. 	*/
/************************************************************************/

int open_window(kind,title,x,y,w,h)
int kind;       	 /* kind of window                     		*/
char *title;         /* window title                          		*/
int x;               /* window X coordinate               		*/
int y;               /* Y                                    		*/
int w;               /* window width             			*/
int h;               /* height                           		*/
  {

  wi_handle = wind_create(kind,xdesk,ydesk,wdesk,hdesk);
  wind_set(wi_handle, WF_NAME,title,0,0);
  graf_growbox(xdesk+wdesk/2,ydesk+hdesk/2,gl_wbox,gl_hbox,x,y,w,h);
  wind_open(wi_handle,x,y,w,h);
  wind_get(wi_handle,WF_WORKXYWH,&xwork,&ywork,&wwork,&hwork);
  return (wi_handle);
  }

/************************************************************************/
/* These routines hide/show the mouse.                          	*/

hide_mouse()
  {
  if(!m_hidden)
    {
     graf_mouse(M_OFF,0x0L);
     m_hidden=TRUE;
     }
  }

show_mouse()
  {
  if(m_hidden)
    {
    graf_mouse(M_ON,0x0L);
    m_hidden=FALSE;
    }
  }

/************************************************************************/
/* File Select Functions												*/
/************************************************************************/

char gu_path[PATH_LEN+1];
char gu_file[FNAME_LEN+1];
char fpath[PATH_LEN+FNAME_LEN+2];

char *get_fname (fdesc)
char *fdesc;
  {
char *lastslash;

  if (sel_file(fdesc))			/* if user seleced file		*/
    {	
    strcpy (fpath,gu_path);		/* copy path to fpath		*/
    lastslash = rindex (fpath,'\\');
    if (lastslash)
      strcpy (lastslash+1,gu_file);	/* add name			*/
    else
      strcpy (fpath,gu_file);
    return (fpath);
    }
  else
    return ((char *)0);
  }

int first_fsel = 1;

int sel_file (fdes)
char *fdes;
  {
int button;
int i;
int drive;
char defpath[80];

  if (first_fsel)	/* first time need to construct path		*/
    {					
    for (i = 0; i < PATH_LEN; ++i)
      gu_path[i] = (char)0;
    for (i = 0; i < FNAME_LEN; ++i)
      gu_file[i] = (char)0;

    drive = Dgetdrv ();		/* get drive ID				*/
    Dgetpath (defpath,0);	/* get current path			*/
    gu_path[0] = drive + 65;	/* get default drive letter		*/	
    strcat (gu_path,":");
    strcat (gu_path,defpath);
    strcat (gu_path,"\\");
    strcat (gu_path,fdes);
    }

  fsel_input (gu_path,gu_file,&button);

  if (button)			/* if user selected, keep path		*/
    first_fsel = 0;
  return (button);
  }

/************************************************************************/
/* Some general user interface routines					*/
/************************************************************************/

wait_msg (str)
char *str;
  {
  v_gtext (vw_handle,xwork+gl_wbox,ywork+gl_hbox,str);
  wait_key ();
  }

wait_key ()
  {
long c;
int stat,x,y;

  while(!(Bconstat(CONSOLE)))
    {
    vq_mouse (vw_handle,&stat,&x,&y);
    if (stat & 3)
      return;
    }    
  while(Bconstat(CONSOLE))
    {
    c = Bconin (CONSOLE);  
    vq_mouse (vw_handle,&stat,&x,&y);
    if (stat & 3)
      return;
    }    
  }

/************************************************************************/
/************************************************************************/
/* Window print functions						*/
/************************************************************************/
/* print a string on a color background  at coordinates x,y		*/

str_print (str,xpos,ypos)
char *str;
int xpos;
int ypos;
  {
int extent[8];
int x,y,w,h;

  vst_alignment (vw_handle,0,2,&x,&x);	/* make x/y top left of str	*/

/*  vqt_extent (vw_handle,str,extent);*//* get box coordinates		*/
/*  w = extent[4];		      */
/*  h = extent[5];		      */

  w = strlen (str) * gl_wbox;
  h = gl_hbox;
  x = xwork+(xpos*gl_wbox);	/* text coordinates			*/
  y = ywork+(ypos*gl_hbox);
  fill_box (x,y,w,h);		/* clear background			*/

  vswr_mode (vw_handle,2);	/* select transparent mode		*/
  v_gtext (vw_handle,x,y,str);
  }

/************************************************************************/
/* print an integer at coordinates x,y									*/

int_print (num,x,y)
int num;
int x;
int y;
  {
char txt[30];
 
  sprintf (txt,"%d",num);	/* convert to string			*/
  str_print (txt,x,y);		/* use string print function		*/
  }

/************************************************************************/

fill_box (x,y,w,h)
int x;			/* top left x					*/
int y;			/* top left y					*/
int w;			/* width					*/
int h;			/* height					*/
  {
int temp[4];

  temp[0]=x;		/* select window				*/
  temp[1]=y+h-1;
  temp[2]=x+w-1;
  temp[3]=y;

  v_bar(vw_handle,temp);            /* write pattern into window   	*/
  }

