
Now we will create function,  which compares structures of databases
and prints a result of the comparison on the screen.

Let's write  a function for  printing of information about  a single
field of a database. Function has the following prototype:

char*	FieldInfo(struct DBF *d, int i);

The function has parameters: a pointer to structure, which describes
DBF-file and field's number. A result  of this function is a string,
which contains a name, a type and a size of the field.


char*
FieldInfo(struct DBF *d, int i)
{
 static char	ret[48];	//resulting string
 char c;

 c=d->fld[i].type;

 //If a  field has a fractional  part our function uses first way of
 //print, otherwise  - second way. The  function GetTypeName returns
 //the type of a field as string.

 if ( (( c=='N' || c== 'F') && d->fld[i].high_len!=0) ||
      (  c=='D' && d->fld[i].low_len==8) )
    wsprintf(ret,
 	"%-11s %-11s %5d %2d",
 	d->fld[i].name,
 	GetTypeName(d, i),
 	d->fld[i].high_len,
 	d->fld[i].low_len
 	);
 else
 {
    wsprintf(ret,
 	"%-11s %-11s %5d   ",
 	d->fld[i].name,
 	GetTypeName(d, i),
 	d->fld[i].high_len
 	);
 }
 return ret;	//pointer to string
}

The second  database can have a  same fields, but placed  not in the
same order.
Therefore we shall need a function, which will determine presence of
a field from first database in second database.

int	field_exist(struct DBF* t1, int i, struct DBF* t2, int *j);

The function has the following parameters:
    t1 - pointer to the first database
    i  - field number in the first database
    t2 - pointer to the second database
    j  - pointer to field number in the second database

Function can return value:
0 - field not found.
1 - field is found, but the type is different.
2 - field is found, it has same type, but the length is different.
3 - field is found, it has same type and same length, but the offset
    from start of record is different.
4 - field is found and all parameters coincide.

To convert the return code to  the text, we will apply the following
symbolic notation, which is used during a print:

char	*cmp[]= {
	"--",	//0
	"<>",	//1
	"~=",	//2
	"= ",	//3
	"=="	//4
	};


Now you can look at our function:

int
field_exist(struct DBF* t1, int i, struct DBF* t2, int *j)
{
 int	k;
 int	ret=0;
 
 for(k=0;k<fieldcount(t2);k++)
  if (!stricmp(t1->fld[i].name, t2->fld[k].name))	//names
   {
     *j=k;	//number of field of second database
     ++ret;
     if (t1->fld[i].type == t2->fld[k].type)		//types
      {
        ++ret;
        if (t1->fld[i].all_len == t2->fld[k].all_len)	//size
         {
	  ++ret;
          if (t1->fld[i].offset == t2->fld[k].offset) ++ret;	//offset
         }
      }
     break; 
   }
      
 return ret;
}


And finally, the function of comparison of structures.

void
CmpStruct()
{
 int	i, j;
 int	ret;
 int	bad=0;	//we will set this value to 1, 
                //when we meet a nonexistent field

 for(i=0;i<fieldcount(d1);i++)		//each field of first database
 {
  switch (ret=field_exist(d1, i, d2, &j))	//checking presence of a field
  {
	case 4:					//if field exist
	case 3:					//to print
	case 2:					//information
	case 1:					//about it
		printf("%-32s", FieldInfo(d1,i));
		printf("  |%2s| ", cmp[ret]);
		printf("%-32s", FieldInfo(d2,j));
		break;
	default:				              //if field does not exist
		printf("%-30s", FieldInfo(d1,i)); //to print information
		printf("  |%2s| ", cmp[0]);	      //about field of the first database only
		printf("%-30s", "-");
		bad=1;				//we have met nonexistent field...
  }
  printf("\n");
 }
 
If the  field count  in the  first database is  less than  the field
count in the  second database or if nonexistent fields  were met, we
will print the rest of the fields of the second database:
 
 if (fieldcount(d1)<fieldcount(d2) || bad)
 {
  for(i=0;i<fieldcount(d2);i++)
  {
   if (!field_exist(d2, i, d1, &j))
     {
	printf("%-32s", "-");
	printf("  |%2s| ", cmp[0]);
	printf("%-32s", FieldInfo(d2,i));
	printf("\n");
     }
  }
 }

}

We can see such a result (or similar to):

POINT       Numeric         5  2  |==| POINT       Numeric         5  2
BIRTHDAY    Date            8     |= | BIRTHDAY    Date            8
FIO         Character      20     |= | FIO         Character      20
HOME        Character      18     |~=| HOME        Character      20
WORK        Character      25     |= | WORK        Character      25
NUM         Character       4     |<>| NUM         Numeric         4  0
LEFT        Numeric         5  0  |--| -
