port_init.c

Go to the documentation of this file.
00001 /*
00002  ****************************************************************************
00003  *
00004  * MODULE:       Vector library 
00005  *              
00006  * AUTHOR(S):    Original author CERL, probably Dave Gerdes.
00007  *               Update to GRASS 5.7 Radim Blazek.
00008  *
00009  * PURPOSE:      Lower level functions for reading/writing/manipulating vectors.
00010  *
00011  * COPYRIGHT:    (C) 2001 by the GRASS Development Team
00012  *
00013  *               This program is free software under the GNU General Public
00014  *              License (>=v2). Read the file COPYING that comes with GRASS
00015  *              for details.
00016  *
00017  *****************************************************************************/
00018 #include <stdio.h>
00019 #include <grass/Vect.h>
00020 
00021 /*
00022  **  Written by Dave Gerdes  9/1988
00023  **  US Army Construction Engineering Research Lab
00024  */
00025 
00026 
00027 /* 
00028  ** 
00029  **  This code is a quick hack to allow the writing of portable
00030  **  binary data files.
00031  **  The approach is to take known values and compare them against
00032  **  the current machine's internal representation.   A cross reference
00033  **  table is then built, and then all file reads and writes must go through
00034  **  through these routines to correct the numbers if need be.
00035  **
00036  **  As long as the byte switching is symetrical, the conversion routines
00037  **  will work both directions.
00038 
00039  **  The integer test patterns are quite simple, and their choice was
00040  **  arbitrary, but the float and double valued were more critical.
00041 
00042  **  I did not have a specification for IEEE to go by, so it is possible
00043  **  that I have missed something.  My criteria were:
00044  **
00045  **  First, true IEEE numbers had to be chosen to avoid getting an FPE.
00046  **  Second, every byte in the test pattern had to be unique.   And
00047  **  finally, the number had to not be sensitive to rounding by the 
00048  **  specific hardware implementation.
00049  **
00050  **  By experimentation it was found that the number  1.3333  met
00051  **  all these criteria for both floats and doubles
00052 
00053  **  See the discourse at the end of this file for more information
00054  **  
00055  **
00056  */
00057 
00058 #define TEST_PATTERN 1.3333
00059 #define LONG_TEST 0x01020304
00060 #define INT_TEST 0x01020304
00061 #define SHORT_TEST 0x0102
00062 
00063 static double u_d = TEST_PATTERN;
00064 static float u_f = TEST_PATTERN;
00065 static long u_l = LONG_TEST;
00066 static int u_i = INT_TEST;
00067 static short u_s = SHORT_TEST;
00068 
00069 /* dbl_cmpr holds the bytes of an IEEE representation of  TEST_PATTERN */
00070 static const unsigned char dbl_cmpr[] =
00071     { 0x3f, 0xf5, 0x55, 0x32, 0x61, 0x7c, 0x1b, 0xda };
00072 /* flt_cmpr holds the bytes of an IEEE representation of  TEST_PATTERN */
00073 static const unsigned char flt_cmpr[] = { 0x3f, 0xaa, 0xa9, 0x93 };
00074 static const unsigned char lng_cmpr[] = { 0x01, 0x02, 0x03, 0x04 };
00075 static const unsigned char int_cmpr[] = { 0x01, 0x02, 0x03, 0x04 };
00076 static const unsigned char shrt_cmpr[] = { 0x01, 0x02 };
00077 
00078 /* Find native sizes */
00079 int nat_dbl = sizeof(double);
00080 int nat_flt = sizeof(float);
00081 int nat_lng = sizeof(long);
00082 int nat_int = sizeof(int);
00083 int nat_shrt = sizeof(short);
00084 
00085 int dbl_order;
00086 int flt_order;
00087 int lng_order;
00088 int int_order;
00089 int shrt_order;
00090 
00091 unsigned char dbl_cnvrt[sizeof(double)];
00092 unsigned char flt_cnvrt[sizeof(float)];
00093 unsigned char lng_cnvrt[sizeof(long)];
00094 unsigned char int_cnvrt[sizeof(int)];
00095 unsigned char shrt_cnvrt[sizeof(short)];
00096 
00097 /*
00098  * match search_value against each char in basis. 
00099  * return offset or -1 if not found
00100  */
00101 
00102 static int find_offset(const unsigned char *basis, unsigned char search_value,
00103                        int size)
00104 {
00105     int i;
00106 
00107     for (i = 0; i < size; i++)
00108         if (basis[i] == search_value)
00109             return (i);
00110 
00111     return (-1);
00112 }
00113 
00114 static int find_offsets(const void *pattern, unsigned char *cnvrt,
00115                         const unsigned char *cmpr, int port_size,
00116                         int nat_size, const char *typename)
00117 {
00118     int big, ltl;
00119     int i;
00120 
00121     for (i = 0; i < port_size; i++) {
00122         int off = find_offset(pattern, cmpr[i], nat_size);
00123 
00124         if (off < 0)
00125             G_fatal_error("could not find '%x' in %s", cmpr[i], typename);
00126 
00127         cnvrt[i] = off;
00128     }
00129 
00130     big = ltl = 1;
00131 
00132     for (i = 0; i < port_size; i++) {
00133         if (cnvrt[i] != (nat_size - port_size + i))
00134             big = 0;            /* isn't big endian */
00135         if (cnvrt[i] != (port_size - 1 - i))
00136             ltl = 0;            /* isn't little endian */
00137     }
00138 
00139     if (big)
00140         return ENDIAN_BIG;
00141 
00142     if (ltl)
00143         return ENDIAN_LITTLE;
00144 
00145     return ENDIAN_OTHER;
00146 }
00147 
00148 void port_init(void)
00149 {
00150     static int done;
00151 
00152     if (done)
00153         return;
00154 
00155     done = 1;
00156 
00157     /* Following code checks only if all assumptions are fullfilled */
00158     /* Check sizes */
00159     if (nat_dbl != PORT_DOUBLE)
00160         G_fatal_error("sizeof(double) != %d", PORT_DOUBLE);
00161     if (nat_flt != PORT_FLOAT)
00162         G_fatal_error("sizeof(float) != %d", PORT_DOUBLE);
00163     if (nat_lng < PORT_LONG)
00164         G_fatal_error("sizeof(long) < %d", PORT_LONG);
00165     if (nat_int < PORT_INT)
00166         G_fatal_error("sizeof(int) < %d", PORT_INT);
00167     if (nat_shrt < PORT_SHORT)
00168         G_fatal_error("sizeof(short) < %d", PORT_SHORT);
00169 
00170     /* Find for each byte in big endian test pattern (*_cmpr) 
00171      * offset of corresponding byte in machine native order.
00172      * Look if native byte order is little or big or some other (pdp)
00173      * endian.
00174      */
00175 
00176     dbl_order =
00177         find_offsets(&u_d, dbl_cnvrt, dbl_cmpr, PORT_DOUBLE, nat_dbl,
00178                      "double");
00179     flt_order =
00180         find_offsets(&u_f, flt_cnvrt, flt_cmpr, PORT_FLOAT, nat_flt, "float");
00181     lng_order =
00182         find_offsets(&u_l, lng_cnvrt, lng_cmpr, PORT_LONG, nat_lng, "long");
00183     int_order =
00184         find_offsets(&u_i, int_cnvrt, int_cmpr, PORT_INT, nat_int, "int");
00185     shrt_order =
00186         find_offsets(&u_s, shrt_cnvrt, shrt_cmpr, PORT_SHORT, nat_shrt,
00187                      "short");
00188 }