GRASS GIS 7 Programmer's Manual  7.9.dev(2021)-e5379bbd7
port_init.c
Go to the documentation of this file.
1 /*!
2  \file diglib/port_init.c
3 
4  \brief Vector library - portability (lower level functions)
5 
6  Lower level functions for reading/writing/manipulating vectors.
7 
8  This code is a quick hack to allow the writing of portable
9  binary data files.
10  The approach is to take known values and compare them against
11  the current machine's internal representation. A cross reference
12  table is then built, and then all file reads and writes must go
13  through these routines to correct the numbers if need be.
14 
15  As long as the byte switching is symmetrical, the conversion routines
16  will work both directions.
17 
18  The integer test patterns are quite simple, and their choice was
19  arbitrary, but the float and double valued were more critical.
20 
21  I did not have a specification for IEEE to go by, so it is possible
22  that I have missed something. My criteria were:
23 
24  First, true IEEE numbers had to be chosen to avoid getting an FPE.
25  Second, every byte in the test pattern had to be unique. And
26  finally, the number had to not be sensitive to rounding by the
27  specific hardware implementation.
28 
29  By experimentation it was found that the number 1.3333 met
30  all these criteria for both floats and doubles
31 
32  See the discourse at the end of this file for more information
33 
34  The 3.0 dig, and dig_plus files are inherently non-portable. This
35  can be seen in moving files between a SUN 386i and other SUN machines.
36  The recommended way to transport files was always to convert to ASCII
37  (b.a.vect) and copy the ASCII files: dig_ascii and dig_att to the
38  destination machine.
39 
40  The problem lies in the way that different architectures internally
41  represent data. If a number is internally store as 0x01020304 on
42  a 680x0 family machine, the same number will be stored as
43  0x04030201 on an 80386 class machine.
44 
45  The CERL port of GRASS to the Compaq 386 already has code to deal
46  with this incompatibility. This code converts all files that are written
47  out to conform to the 680x0 standard. These binary files can then be
48  shared between machines without conversion.
49  This code is designed to work with the majority of computers in use
50  today that fit the following requirements:
51  byte == 8 bits
52  int == 4 bytes
53  long == 4 bytes
54  double == IEEE standard 64 bit
55  float == IEEE standard 32 bit
56 
57  bytes can be swapped around in any reasonable way, but bits within each
58  byte must be maintained in normal high to low ordering: 76543210
59  is this a problem?
60 
61  If this ability is desired on a SUN 386i, for example, you simply
62  define the compiler flag CERL_PORTABLE in the src/CMD/makehead file
63  and recompile all of the mapdev programs.
64  needs update, makehead/mapdev no longer exist
65 
66  Binary DLG files are NOT supported by this code, and will continue to
67  be non-portable between different architectures.
68  applies to the files coor/topo/cidx, needs testing
69 
70  (C) 2001-2009 by the GRASS Development Team
71 
72  This program is free software under the GNU General Public License
73  (>=v2). Read the file COPYING that comes with GRASS for details.
74 
75  \author Original author CERL, probably Dave Gerdes
76  \author Update to GRASS 5.7 Radim Blazek
77 */
78 
79 #include <stdio.h>
80 #include <sys/types.h>
81 #include <grass/vector.h>
82 #include <grass/glocale.h>
83 
84 #define TEST_PATTERN 1.3333
85 #ifdef HAVE_LONG_LONG_INT
86 #define LONG_LONG_TEST 0x0102030405060708LL
87 #endif
88 #define LONG_TEST 0x01020304
89 #define INT_TEST 0x01020304
90 #define SHORT_TEST 0x0102
91 
92 static double u_d = TEST_PATTERN;
93 static float u_f = TEST_PATTERN;
94 off_t u_o; /* depends on sizeof(off_t) */
95 static long u_l = LONG_TEST;
96 static int u_i = INT_TEST;
97 static short u_s = SHORT_TEST;
98 
99 /* dbl_cmpr holds the bytes of an IEEE representation of TEST_PATTERN */
100 static const unsigned char dbl_cmpr[] =
101  { 0x3f, 0xf5, 0x55, 0x32, 0x61, 0x7c, 0x1b, 0xda };
102 /* flt_cmpr holds the bytes of an IEEE representation of TEST_PATTERN */
103 static const unsigned char flt_cmpr[] = { 0x3f, 0xaa, 0xa9, 0x93 };
104 static const unsigned char off_t_cmpr[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
105 static const unsigned char lng_cmpr[] = { 0x01, 0x02, 0x03, 0x04 };
106 static const unsigned char int_cmpr[] = { 0x01, 0x02, 0x03, 0x04 };
107 static const unsigned char shrt_cmpr[] = { 0x01, 0x02 };
108 
109 /* Find native sizes */
110 int nat_dbl = sizeof(double);
111 int nat_flt = sizeof(float);
112 int nat_off_t = sizeof(off_t);
113 int nat_lng = sizeof(long);
114 int nat_int = sizeof(int);
115 int nat_shrt = sizeof(short);
116 
123 
124 unsigned char dbl_cnvrt[sizeof(double)];
125 unsigned char flt_cnvrt[sizeof(float)];
126 unsigned char off_t_cnvrt[sizeof(off_t)];
127 unsigned char lng_cnvrt[sizeof(long)];
128 unsigned char int_cnvrt[sizeof(int)];
129 unsigned char shrt_cnvrt[sizeof(short)];
130 
131 /*
132  * match search_value against each char in basis.
133  * return offset or -1 if not found
134  */
135 static int find_offset(const unsigned char *basis, unsigned char search_value,
136  int size)
137 {
138  int i;
139 
140  for (i = 0; i < size; i++)
141  if (basis[i] == search_value)
142  return (i);
143 
144  return (-1);
145 }
146 
147 static int find_offsets(const void *pattern, unsigned char *cnvrt,
148  const unsigned char *cmpr, int port_size,
149  int nat_size, const char *typename)
150 {
151  int big, ltl;
152  int i;
153 
154  for (i = 0; i < port_size; i++) {
155  int off = find_offset(pattern, cmpr[i], nat_size);
156 
157  if (off < 0)
158  G_fatal_error(_("Unable to find '%x' in %s"), cmpr[i], typename);
159 
160  cnvrt[i] = off;
161  }
162 
163  big = ltl = 1;
164 
165  for (i = 0; i < port_size; i++) {
166  if (cnvrt[i] != (nat_size - port_size + i))
167  big = 0; /* isn't big endian */
168  if (cnvrt[i] != (port_size - 1 - i))
169  ltl = 0; /* isn't little endian */
170  }
171 
172  if (big)
173  return ENDIAN_BIG;
174 
175  if (ltl)
176  return ENDIAN_LITTLE;
177 
178  return ENDIAN_OTHER;
179 }
180 
181 /*!
182  \brief Initialize Port_info structures
183 */
184 void port_init(void)
185 {
186  static int done;
187 
188  if (done)
189  return;
190 
191  done = 1;
192 
193  /* Following code checks only if all assumptions are fulfilled */
194  /* Check sizes */
195  if (nat_dbl != PORT_DOUBLE)
196  G_fatal_error("sizeof(double) != %d", PORT_DOUBLE);
197  if (nat_flt != PORT_FLOAT)
198  G_fatal_error("sizeof(float) != %d", PORT_DOUBLE);
199  /* off_t size is variable, depending on the vector size and LFS support */
200  if (nat_lng < PORT_LONG)
201  G_fatal_error("sizeof(long) < %d", PORT_LONG);
202  if (nat_int < PORT_INT)
203  G_fatal_error("sizeof(int) < %d", PORT_INT);
204  if (nat_shrt < PORT_SHORT)
205  G_fatal_error("sizeof(short) < %d", PORT_SHORT);
206 
207  /* Find for each byte in big endian test pattern (*_cmpr)
208  * offset of corresponding byte in machine native order.
209  * Look if native byte order is little or big or some other (pdp)
210  * endian.
211  */
212 
213  if (nat_off_t == 8)
214 #ifdef HAVE_LONG_LONG_INT
215  u_o = (off_t) LONG_LONG_TEST;
216 #else
217  G_fatal_error("Internal error: can't construct an off_t literal");
218 #endif
219  else
220  u_o = (off_t) LONG_TEST;
221 
222  dbl_order =
223  find_offsets(&u_d, dbl_cnvrt, dbl_cmpr, PORT_DOUBLE, nat_dbl,
224  "double");
225  flt_order =
226  find_offsets(&u_f, flt_cnvrt, flt_cmpr, PORT_FLOAT, nat_flt, "float");
227  off_t_order =
228  find_offsets(&u_o, off_t_cnvrt, off_t_cmpr, nat_off_t, nat_off_t, "off_t");
229  lng_order =
230  find_offsets(&u_l, lng_cnvrt, lng_cmpr, PORT_LONG, nat_lng, "long");
231  int_order =
232  find_offsets(&u_i, int_cnvrt, int_cmpr, PORT_INT, nat_int, "int");
233  shrt_order =
234  find_offsets(&u_s, shrt_cnvrt, shrt_cmpr, PORT_SHORT, nat_shrt,
235  "short");
236 }
#define PORT_FLOAT
Definition: dig_defines.h:46
#define ENDIAN_LITTLE
Endian check.
Definition: gis.h:380
#define PORT_SHORT
Definition: dig_defines.h:49
#define TEST_PATTERN
Definition: port_init.c:84
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
unsigned char lng_cnvrt[sizeof(long)]
Definition: port_init.c:127
#define ENDIAN_OTHER
Definition: gis.h:382
int nat_lng
Definition: port_init.c:113
int nat_dbl
Definition: port_init.c:110
int nat_off_t
Definition: port_init.c:112
int off_t_order
Definition: port_init.c:119
#define PORT_LONG
Definition: dig_defines.h:47
int nat_flt
Definition: port_init.c:111
int flt_order
Definition: port_init.c:118
#define PORT_DOUBLE
Sizes of types used in portable format (different names used in Vlib/ and diglib/ for the same thing)...
Definition: dig_defines.h:45
#define LONG_LONG_TEST
Definition: port_init.c:86
off_t u_o
Definition: port_init.c:94
#define ENDIAN_BIG
Definition: gis.h:381
unsigned char off_t_cnvrt[sizeof(off_t)]
Definition: port_init.c:126
unsigned char dbl_cnvrt[sizeof(double)]
Definition: port_init.c:124
#define INT_TEST
Definition: port_init.c:89
int dbl_order
Definition: port_init.c:117
int nat_shrt
Definition: port_init.c:115
int nat_int
Definition: port_init.c:114
int int_order
Definition: port_init.c:121
int lng_order
Definition: port_init.c:120
int shrt_order
Definition: port_init.c:122
unsigned char int_cnvrt[sizeof(int)]
Definition: port_init.c:128
#define LONG_TEST
Definition: port_init.c:88
unsigned char shrt_cnvrt[sizeof(short)]
Definition: port_init.c:129
#define _(str)
Definition: glocale.h:10
#define SHORT_TEST
Definition: port_init.c:90
#define PORT_INT
Definition: dig_defines.h:48
unsigned char flt_cnvrt[sizeof(float)]
Definition: port_init.c:125
void port_init(void)
Initialize Port_info structures.
Definition: port_init.c:184