port_test.c

Go to the documentation of this file.
00001 /*
00002 * $Id: port_test.c,v 1.6 2006/02/09 03:08:58 glynn Exp $
00003 *
00004 ****************************************************************************
00005 *
00006 * MODULE:       Vector library 
00007 *               
00008 * AUTHOR(S):    Original author CERL, probably Dave Gerdes.
00009 *               Update to GRASS 5.7 Radim Blazek.
00010 *
00011 * PURPOSE:      Lower level functions for reading/writing/manipulating vectors.
00012 *
00013 * COPYRIGHT:    (C) 2001 by the GRASS Development Team
00014 *
00015 *               This program is free software under the GNU General Public
00016 *               License (>=v2). Read the file COPYING that comes with GRASS
00017 *               for details.
00018 *
00019 *****************************************************************************/
00020 #include <stdio.h>
00021 #include <grass/Vect.h>
00022 
00023 /*
00024    **  Written by Dave Gerdes  9/1988
00025    **  US Army Construction Engineering Research Lab
00026  */
00027 
00028 
00029 /* 
00030    ** 
00031    **  This code is a quick hack to allow the writing of portable
00032    **  binary data files.
00033    **  The approach is to take known values and compare them against
00034    **  the current machine's internal representation.   A cross reference
00035    **  table is then built, and then all file reads and writes must go through
00036    **  through these routines to correct the numbers if need be.
00037    **
00038    **  As long as the byte switching is symetrical, the conversion routines
00039    **  will work both directions.
00040 
00041    **  The integer test patterns are quite simple, and their choice was
00042    **  arbitrary, but the float and double valued were more critical.
00043 
00044    **  I did not have a specification for IEEE to go by, so it is possible
00045    **  that I have missed something.  My criteria were:
00046    **
00047    **  First, true IEEE numbers had to be chosen to avoid getting an FPE.
00048    **  Second, every byte in the test pattern had to be unique.   And
00049    **  finally, the number had to not be sensitive to rounding by the 
00050    **  specific hardware implementation.
00051    **
00052    **  By experimentation it was found that the number  1.3333  met
00053    **  all these criteria for both floats and doubles
00054 
00055    **  See the discourse at the end of this file for more information
00056    **  
00057    **
00058  */
00059 
00060 #define TEST_PATTERN 1.3333
00061 #define LONG_TEST 0x01020304
00062 #define INT_TEST 0x01020304
00063 #define SHORT_TEST 0x0102
00064 
00065 union type_conv
00066   {
00067     double d;
00068     float f;
00069     long l;
00070     int  i;
00071     short s;
00072     unsigned char c[PORT_DOUBLE];
00073   };
00074 static union type_conv u;
00075 
00076 /* dbl_cmpr holds the bytes of an IEEE representation of  TEST_PATTERN */
00077 static unsigned char dbl_cmpr[] =
00078 {0x3f, 0xf5, 0x55, 0x32, 0x61, 0x7c, 0x1b, 0xda};
00079 /* flt_cmpr holds the bytes of an IEEE representation of  TEST_PATTERN */
00080 static unsigned char flt_cmpr[] =
00081 {0x3f, 0xaa, 0xa9, 0x93};
00082 static unsigned char lng_cmpr[] =
00083 {0x01, 0x02, 0x03, 0x04};
00084 static unsigned char int_cmpr[] =
00085 {0x01, 0x02, 0x03, 0x04};
00086 static unsigned char shrt_cmpr[] =
00087 {0x01, 0x02};
00088 
00089 static char dbl_cnvrt[sizeof (double)];
00090 static char flt_cnvrt[sizeof (float)];
00091 static char lng_cnvrt[sizeof (long)];
00092 static char int_cnvrt[sizeof (int)];
00093 static char shrt_cnvrt[sizeof (short)];
00094 
00095 static int nat_dbl, nat_flt, nat_lng, nat_int, nat_shrt, nat_char;
00096 
00097 
00098 /* function prototypes */
00099 static int find_offset (unsigned char *, unsigned char, int);
00100 static int dumpflags (void);
00101 
00102 
00103 int 
00104 main (int argc, char **argv)
00105 {
00106   register int i;
00107   int tmp, tmp2;
00108   int err = 0;
00109   int dbl_order, flt_order, lng_order, int_order, shrt_order;
00110   
00111   /* Find native sizes */
00112   printf ("\n/* Native machine sizes */\n");
00113   printf ("#define NATIVE_DOUBLE %d\n", (nat_dbl = sizeof (double)));
00114   printf ("#define NATIVE_FLOAT  %d\n", (nat_flt = sizeof (float)));
00115   printf ("#define NATIVE_LONG   %d\n", (nat_lng = sizeof (long)));
00116   printf ("#define NATIVE_INT    %d\n", (nat_int = sizeof (int)));
00117   printf ("#define NATIVE_SHORT  %d\n", (nat_shrt = sizeof (short)));
00118   printf ("#define NATIVE_CHAR   %d\n", (nat_char = sizeof (char)));
00119 
00120   /* Following code checks only if all assumptions are fullfilled */
00121   /* Check sizes */           
00122   if (nat_dbl != PORT_DOUBLE)
00123     {
00124       fprintf (stderr, "ERROR, sizeof (double) != %d\n", PORT_DOUBLE);
00125       err = 1;
00126     }
00127   if (nat_flt != PORT_FLOAT)
00128     {
00129       fprintf (stderr, "ERROR, sizeof (float) != %d\n", PORT_DOUBLE);
00130       err = 1;
00131     }
00132   if (nat_lng < PORT_LONG)
00133     {
00134       fprintf (stderr, "ERROR, sizeof (long) < %d\n", PORT_LONG);
00135       err = 1;
00136     }
00137   if (nat_int < PORT_INT)
00138     {
00139       fprintf (stderr, "ERROR, sizeof (int) < %d\n", PORT_INT);
00140       err = 1;
00141     }
00142   if (nat_shrt < PORT_SHORT)
00143     {
00144       fprintf (stderr, "ERROR, sizeof (short) < %d\n", PORT_SHORT);
00145       err = 1;
00146     }
00147   if (nat_char != PORT_CHAR)
00148     {
00149       fprintf (stderr, "ERROR, sizeof (char) != %d\n", PORT_CHAR);
00150       err = 1;
00151     }
00152       
00153   /* Find for each byte in big endian test pattern (*_cmpr) 
00154    * offset of corresponding byte in machine native order.
00155    * Look if native byte order is little or big or some other (pdp)
00156    * endian.
00157    */
00158   /* Find double order */ 
00159   u.d = TEST_PATTERN;
00160   for (i = 0; i < PORT_DOUBLE; i++)
00161     {     
00162       tmp = find_offset (u.c, dbl_cmpr[i], PORT_DOUBLE);
00163       if (-1 == tmp)
00164         {         
00165           fprintf (stderr, "ERROR, could not find '%x' in double\n", dbl_cmpr[i]);
00166           err = 1;
00167         }
00168       dbl_cnvrt[i] = tmp;
00169     }
00170   tmp = tmp2 = 1;
00171   for (i = 0; i < PORT_DOUBLE; i++)
00172     {
00173       if ( dbl_cnvrt[i] != i ) tmp = 0;              /* isn't big endian */
00174       if ( dbl_cnvrt[i] != (PORT_DOUBLE - i - 1 )) tmp2 = 0; /* isn't little endian */  
00175     }  
00176   if ( tmp ) dbl_order = ENDIAN_BIG;
00177   else if ( tmp2 ) dbl_order = ENDIAN_LITTLE;
00178   else dbl_order = ENDIAN_OTHER;
00179           
00180   /* Find float order */
00181   u.f = TEST_PATTERN;
00182   for (i = 0; i < PORT_FLOAT; i++)
00183     {     
00184       tmp = find_offset (u.c, flt_cmpr[i], PORT_FLOAT);
00185       if (-1 == tmp)
00186         {         
00187           fprintf (stderr, "ERROR, could not find '%x' in float\n", flt_cmpr[i]);
00188           err = 1;
00189         }
00190       flt_cnvrt[i] = tmp;
00191     }
00192   tmp = tmp2 = 1;
00193   for (i = 0; i < PORT_FLOAT; i++)
00194     {
00195       if ( flt_cnvrt[i] != i ) tmp = 0;
00196       if ( flt_cnvrt[i] != (PORT_FLOAT - i - 1 )) tmp2 = 0;
00197     }  
00198   if ( tmp ) flt_order = ENDIAN_BIG;
00199   else if ( tmp2 ) flt_order = ENDIAN_LITTLE;
00200   else flt_order = ENDIAN_OTHER;
00201 
00202   /* Find long order */
00203   u.l = LONG_TEST;
00204   for (i = 0; i < PORT_LONG; i++)
00205     {     
00206       tmp = find_offset (u.c, lng_cmpr[i], nat_lng);
00207       if (-1 == tmp)
00208         {         
00209           fprintf (stderr, "ERROR, could not find '%x' in long\n", lng_cmpr[i]);
00210           err = 1;
00211         }
00212       lng_cnvrt[i] = tmp;
00213     }
00214   tmp = tmp2 = 1;
00215   for (i = 0; i < PORT_LONG; i++)
00216     {
00217       if ( lng_cnvrt[i] != ( i + ( nat_lng - PORT_LONG) ) ) tmp = 0;
00218       if ( lng_cnvrt[i] != (PORT_LONG - i - 1 )) tmp2 = 0;
00219     }  
00220   if ( tmp ) lng_order = ENDIAN_BIG;
00221   else if ( tmp2 ) lng_order = ENDIAN_LITTLE;
00222   else lng_order = ENDIAN_OTHER;
00223   
00224   /* Find int order */
00225   u.i = INT_TEST;
00226   for (i = 0; i < PORT_INT; i++)
00227     {     
00228       tmp = find_offset (u.c, int_cmpr[i], nat_int);
00229       if (-1 == tmp)
00230         {         
00231           fprintf (stderr, "ERROR, could not find '%x' in int\n", int_cmpr[i]);
00232           err = 1;
00233         }
00234       int_cnvrt[i] = tmp;
00235     }
00236   tmp = tmp2 = 1;
00237   for (i = 0; i < PORT_INT; i++)
00238     {
00239       if ( int_cnvrt[i] != ( i + ( nat_lng - PORT_LONG) ) ) tmp = 0;
00240       if ( int_cnvrt[i] != (PORT_INT - i - 1 )) tmp2 = 0;
00241     }  
00242   if ( tmp ) int_order = ENDIAN_BIG;
00243   else if ( tmp2 ) int_order = ENDIAN_LITTLE;
00244   else int_order = ENDIAN_OTHER;
00245   
00246   /* Find short order */
00247   u.s = SHORT_TEST;
00248   for (i = 0; i < PORT_SHORT; i++)
00249     {     
00250       tmp = find_offset (u.c, shrt_cmpr[i], nat_shrt);
00251       if (-1 == tmp)
00252         {         
00253           fprintf (stderr, "ERROR, could not find '%x' in shrt\n", shrt_cmpr[i]);
00254           err = 1;
00255         }
00256       shrt_cnvrt[i] = tmp;
00257     }
00258   tmp = tmp2 = 1;
00259   for (i = 0; i < PORT_SHORT; i++)
00260     {
00261       if ( shrt_cnvrt[i] != ( i + ( nat_shrt - PORT_SHORT) ) ) tmp = 0;
00262       if ( shrt_cnvrt[i] != (PORT_SHORT - i - 1 )) tmp2 = 0;
00263     }  
00264   if ( tmp ) shrt_order = ENDIAN_BIG;
00265   else if ( tmp2 ) shrt_order = ENDIAN_LITTLE;
00266   else shrt_order = ENDIAN_OTHER;
00267 
00268   printf ("\n/* Native machine byte orders */\n");
00269   printf ("#define DOUBLE_ORDER %d\n", dbl_order);
00270   printf ("#define FLOAT_ORDER  %d\n", flt_order);
00271   printf ("#define LONG_ORDER   %d\n", lng_order);
00272   printf ("#define INT_ORDER    %d\n", int_order);
00273   printf ("#define SHORT_ORDER  %d\n", shrt_order);
00274   
00275   printf ("\n\n/* Translation matrices from big endian to native */\n");
00276   dumpflags ();
00277 
00278   return (err);
00279 }
00280 
00281 
00282 /*
00283    ** match search_value against each char in basis. 
00284    ** return offset or -1 if not found
00285  */
00286 static int 
00287 find_offset (unsigned char *basis, unsigned char search_value, int size)
00288 {
00289   register int i;
00290 
00291   for (i = 0; i < size; i++)
00292     if (basis[i] == search_value)
00293       return (i);
00294 
00295   return (-1);
00296 }
00297 
00298 
00299 static int dumpflags (void)
00300 {
00301   int i;
00302 
00303   fprintf (stdout, "\n/* Double format: */\nstatic int dbl_cnvrt[] = {");
00304   i = 0;
00305   while (i < nat_dbl)
00306     {
00307       fprintf (stdout, "%d", dbl_cnvrt[i]);
00308       if (++i < nat_dbl)
00309         fprintf (stdout, ", ");
00310     }
00311   fprintf (stdout, "};\n\n");
00312 
00313   fprintf (stdout, "/* Float format : */\nstatic int flt_cnvrt[] = {");
00314   i = 0;
00315   while (i < nat_flt)
00316     {
00317       fprintf (stdout, "%d", flt_cnvrt[i]);
00318       if (++i < nat_flt)
00319         fprintf (stdout, ", ");
00320     }
00321   fprintf (stdout, "};\n\n");
00322 
00323   fprintf (stdout, "/* Long format  : */\nstatic int lng_cnvrt[] = {");
00324   i = 0;
00325   while (i < nat_lng)
00326     {
00327       fprintf (stdout, "%d", lng_cnvrt[i]);
00328       if (++i < nat_lng)
00329         fprintf (stdout, ", ");
00330     }
00331   fprintf (stdout, "};\n\n");
00332   
00333   fprintf (stdout, "/* Int format  : */\nstatic int int_cnvrt[] = {");
00334   i = 0;
00335   while (i < nat_int)
00336     {
00337       fprintf (stdout, "%d", int_cnvrt[i]);
00338       if (++i < nat_int)
00339         fprintf (stdout, ", ");
00340     }
00341   fprintf (stdout, "};\n\n");
00342 
00343   fprintf (stdout, "/* Short format : */\nstatic int shrt_cnvrt[] = {");
00344   i = 0;
00345   while (i < nat_shrt)
00346     {
00347       fprintf (stdout, "%d", shrt_cnvrt[i]);
00348       if (++i < nat_shrt)
00349         fprintf (stdout, ", ");
00350     }
00351   fprintf (stdout, "};\n\n");
00352 
00353   return 0;
00354 }
00355 
00356 /*
00357 
00358    The 3.0 dig, and dig_plus files are inherently non-portable.  This 
00359    can be seen in moving files between a SUN 386i and other SUN machines.
00360    The recommended way to transport files was always to convert to ASCII
00361    (b.a.vect) and copy the ASCII files:  dig_ascii and dig_att to the 
00362    destination machine.
00363 
00364    The problem lies in the way that different architectures internally
00365    represent data.   If a number is internally store as  0x01020304 on
00366    a 680x0 family machine, the same number will be stored as
00367    0x04030201 on an 80386 class machine.
00368 
00369    The CERL port of GRASS to the Compaq 386 already has code to deal
00370    with this incompatibility.  This code converts all files that are written
00371    out to conform to the 680x0 standard.  These binary files can then be 
00372    shared between machines without conversion.
00373    This code is designed to work with the majority of computers in use
00374    today that fit the following requirements:
00375    byte     ==  8 bits
00376    int      ==  4 bytes
00377    long     ==  4 bytes
00378    double   ==  IEEE standard 64 bit
00379    float    ==  IEEE standard 32 bit
00380    bytes can be swapped around in any reasonable way, but bits within each
00381    byte must be maintained in normal high to low ordering:  76543210
00382 
00383    If this ability is desired on a SUN 386i, for example, you simply
00384    define the compiler flag  CERL_PORTABLE in the src/CMD/makehead  file
00385    and recompile all of the mapdev programs.
00386 
00387 
00388    Binary DLG files are NOT supported by this code, and will continue to
00389    be non-portable between different architectures.
00390 
00391 
00392    -dave gerdes
00393  */

Generated on Sun Apr 6 17:32:44 2008 for GRASS by  doxygen 1.5.5