GRASS GIS 7 Programmer's Manual  7.9.dev(2021)-e5379bbd7
port_test.c
Go to the documentation of this file.
1 /*
2  ****************************************************************************
3  *
4  * MODULE: Vector library
5  *
6  * AUTHOR(S): Original author CERL, probably Dave Gerdes.
7  * Update to GRASS 5.7 Radim Blazek.
8  *
9  * PURPOSE: Lower level functions for reading/writing/manipulating vectors.
10  *
11  * COPYRIGHT: (C) 2001 by the GRASS Development Team
12  *
13  * This program is free software under the GNU General Public
14  * License (>=v2). Read the file COPYING that comes with GRASS
15  * for details.
16  *
17  *****************************************************************************/
18 #include <stdio.h>
19 #include <sys/types.h>
20 #include <grass/vector.h>
21 
22 /*
23  ** Written by Dave Gerdes 9/1988
24  ** US Army Construction Engineering Research Lab
25  */
26 
27 
28 /*
29  **
30  ** This code is a quick hack to allow the writing of portable
31  ** binary data files.
32  ** The approach is to take known values and compare them against
33  ** the current machine's internal representation. A cross reference
34  ** table is then built, and then all file reads and writes must go through
35  ** through these routines to correct the numbers if need be.
36  **
37  ** As long as the byte switching is symmetrical, the conversion routines
38  ** will work both directions.
39 
40  ** The integer test patterns are quite simple, and their choice was
41  ** arbitrary, but the float and double valued were more critical.
42 
43  ** I did not have a specification for IEEE to go by, so it is possible
44  ** that I have missed something. My criteria were:
45  **
46  ** First, true IEEE numbers had to be chosen to avoid getting an FPE.
47  ** Second, every byte in the test pattern had to be unique. And
48  ** finally, the number had to not be sensitive to rounding by the
49  ** specific hardware implementation.
50  **
51  ** By experimentation it was found that the number 1.3333 met
52  ** all these criteria for both floats and doubles
53 
54  ** See the discourse at the end of this file for more information
55  **
56  **
57  */
58 
59 #define TEST_PATTERN 1.3333
60 #ifdef HAVE_LONG_LONG_INT
61 #define OFF_T_TEST 0x0102030405060708LL
62 #else
63 #define OFF_T_TEST 0x01020304
64 #endif
65 #define LONG_TEST 0x01020304
66 #define INT_TEST 0x01020304
67 #define SHORT_TEST 0x0102
68 
69 union type_conv
70 {
71  double d;
72  float f;
73  off_t o;
74  long l;
75  int i;
76  short s;
77  unsigned char c[PORT_DOUBLE];
78 };
79 static union type_conv u;
80 
81 /* dbl_cmpr holds the bytes of an IEEE representation of TEST_PATTERN */
82 static unsigned char dbl_cmpr[] =
83  { 0x3f, 0xf5, 0x55, 0x32, 0x61, 0x7c, 0x1b, 0xda };
84 /* flt_cmpr holds the bytes of an IEEE representation of TEST_PATTERN */
85 static unsigned char flt_cmpr[] = { 0x3f, 0xaa, 0xa9, 0x93 };
86 static unsigned char off_t_cmpr[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
87 static unsigned char lng_cmpr[] = { 0x01, 0x02, 0x03, 0x04 };
88 static unsigned char int_cmpr[] = { 0x01, 0x02, 0x03, 0x04 };
89 static unsigned char shrt_cmpr[] = { 0x01, 0x02 };
90 
91 static char dbl_cnvrt[sizeof(double)];
92 static char flt_cnvrt[sizeof(float)];
93 static char off_t_cnvrt[sizeof(off_t)];
94 static char lng_cnvrt[sizeof(long)];
95 static char int_cnvrt[sizeof(int)];
96 static char shrt_cnvrt[sizeof(short)];
97 
98 static int nat_dbl, nat_flt, nat_lng, nat_off_t, nat_int, nat_shrt, nat_char;
99 
100 
101 /* function prototypes */
102 static int find_offset(unsigned char *, unsigned char, int);
103 static int dumpflags(void);
104 
105 
106 int main(int argc, char **argv)
107 {
108  register int i;
109  int tmp, tmp2;
110  int err = 0;
112 
113  /* Find native sizes */
114  printf("\n/* Native machine sizes */\n");
115  printf("#define NATIVE_DOUBLE %d\n", (nat_dbl = sizeof(double)));
116  printf("#define NATIVE_FLOAT %d\n", (nat_flt = sizeof(float)));
117  printf("#define NATIVE_OFF_T %d\n", (nat_off_t = sizeof(off_t)));
118  printf("#define NATIVE_LONG %d\n", (nat_lng = sizeof(long)));
119  printf("#define NATIVE_INT %d\n", (nat_int = sizeof(int)));
120  printf("#define NATIVE_SHORT %d\n", (nat_shrt = sizeof(short)));
121  printf("#define NATIVE_CHAR %d\n", (nat_char = sizeof(char)));
122 
123  /* Following code checks only if all assumptions are fulfilled */
124  /* Check sizes */
125  if (nat_dbl != PORT_DOUBLE) {
126  fprintf(stderr, "ERROR, sizeof (double) != %d\n", PORT_DOUBLE);
127  err = 1;
128  }
129  if (nat_flt != PORT_FLOAT) {
130  fprintf(stderr, "ERROR, sizeof (float) != %d\n", PORT_FLOAT);
131  err = 1;
132  }
133  /* port_off_t is variable */
134  if (nat_lng < PORT_LONG) {
135  fprintf(stderr, "ERROR, sizeof (long) < %d\n", PORT_LONG);
136  err = 1;
137  }
138  if (nat_int < PORT_INT) {
139  fprintf(stderr, "ERROR, sizeof (int) < %d\n", PORT_INT);
140  err = 1;
141  }
142  if (nat_shrt < PORT_SHORT) {
143  fprintf(stderr, "ERROR, sizeof (short) < %d\n", PORT_SHORT);
144  err = 1;
145  }
146  if (nat_char != PORT_CHAR) {
147  fprintf(stderr, "ERROR, sizeof (char) != %d\n", PORT_CHAR);
148  err = 1;
149  }
150 
151  /* Find for each byte in big endian test pattern (*_cmpr)
152  * offset of corresponding byte in machine native order.
153  * Look if native byte order is little or big or some other (pdp)
154  * endian.
155  */
156  /* Find double order */
157  u.d = TEST_PATTERN;
158  for (i = 0; i < PORT_DOUBLE; i++) {
159  tmp = find_offset(u.c, dbl_cmpr[i], PORT_DOUBLE);
160  if (-1 == tmp) {
161  fprintf(stderr, "ERROR, could not find '%x' in double\n",
162  dbl_cmpr[i]);
163  err = 1;
164  }
165  dbl_cnvrt[i] = tmp;
166  }
167  tmp = tmp2 = 1;
168  for (i = 0; i < PORT_DOUBLE; i++) {
169  if (dbl_cnvrt[i] != i)
170  tmp = 0; /* isn't big endian */
171  if (dbl_cnvrt[i] != (PORT_DOUBLE - i - 1))
172  tmp2 = 0; /* isn't little endian */
173  }
174  if (tmp)
175  dbl_order = ENDIAN_BIG;
176  else if (tmp2)
177  dbl_order = ENDIAN_LITTLE;
178  else
179  dbl_order = ENDIAN_OTHER;
180 
181  /* Find float order */
182  u.f = TEST_PATTERN;
183  for (i = 0; i < PORT_FLOAT; i++) {
184  tmp = find_offset(u.c, flt_cmpr[i], PORT_FLOAT);
185  if (-1 == tmp) {
186  fprintf(stderr, "ERROR, could not find '%x' in float\n",
187  flt_cmpr[i]);
188  err = 1;
189  }
190  flt_cnvrt[i] = tmp;
191  }
192  tmp = tmp2 = 1;
193  for (i = 0; i < PORT_FLOAT; i++) {
194  if (flt_cnvrt[i] != i)
195  tmp = 0;
196  if (flt_cnvrt[i] != (PORT_FLOAT - i - 1))
197  tmp2 = 0;
198  }
199  if (tmp)
200  flt_order = ENDIAN_BIG;
201  else if (tmp2)
202  flt_order = ENDIAN_LITTLE;
203  else
204  flt_order = ENDIAN_OTHER;
205 
206  /* Find off_t order */
207  if (nat_off_t == 8)
208  u.o = OFF_T_TEST;
209  else
210  u.o = LONG_TEST;
211  for (i = 0; i < nat_off_t; i++) {
212  tmp = find_offset(u.c, off_t_cmpr[i], nat_off_t);
213  if (-1 == tmp) {
214  fprintf(stderr, "ERROR, could not find '%x' in off_t\n",
215  off_t_cmpr[i]);
216  err = 1;
217  }
218  off_t_cnvrt[i] = tmp;
219  }
220  tmp = tmp2 = 1;
221  for (i = 0; i < nat_off_t; i++) {
222  if (off_t_cnvrt[i] != (i + (nat_off_t - nat_off_t)))
223  tmp = 0;
224  if (off_t_cnvrt[i] != (nat_off_t - i - 1))
225  tmp2 = 0;
226  }
227  if (tmp)
229  else if (tmp2)
231  else
233 
234  /* Find long order */
235  u.l = LONG_TEST;
236  for (i = 0; i < PORT_LONG; i++) {
237  tmp = find_offset(u.c, lng_cmpr[i], nat_lng);
238  if (-1 == tmp) {
239  fprintf(stderr, "ERROR, could not find '%x' in long\n",
240  lng_cmpr[i]);
241  err = 1;
242  }
243  lng_cnvrt[i] = tmp;
244  }
245  tmp = tmp2 = 1;
246  for (i = 0; i < PORT_LONG; i++) {
247  if (lng_cnvrt[i] != (i + (nat_lng - PORT_LONG)))
248  tmp = 0;
249  if (lng_cnvrt[i] != (PORT_LONG - i - 1))
250  tmp2 = 0;
251  }
252  if (tmp)
253  lng_order = ENDIAN_BIG;
254  else if (tmp2)
255  lng_order = ENDIAN_LITTLE;
256  else
257  lng_order = ENDIAN_OTHER;
258 
259  /* Find int order */
260  u.i = INT_TEST;
261  for (i = 0; i < PORT_INT; i++) {
262  tmp = find_offset(u.c, int_cmpr[i], nat_int);
263  if (-1 == tmp) {
264  fprintf(stderr, "ERROR, could not find '%x' in int\n",
265  int_cmpr[i]);
266  err = 1;
267  }
268  int_cnvrt[i] = tmp;
269  }
270  tmp = tmp2 = 1;
271  for (i = 0; i < PORT_INT; i++) {
272  if (int_cnvrt[i] != (i + (nat_lng - PORT_LONG)))
273  tmp = 0;
274  if (int_cnvrt[i] != (PORT_INT - i - 1))
275  tmp2 = 0;
276  }
277  if (tmp)
278  int_order = ENDIAN_BIG;
279  else if (tmp2)
280  int_order = ENDIAN_LITTLE;
281  else
282  int_order = ENDIAN_OTHER;
283 
284  /* Find short order */
285  u.s = SHORT_TEST;
286  for (i = 0; i < PORT_SHORT; i++) {
287  tmp = find_offset(u.c, shrt_cmpr[i], nat_shrt);
288  if (-1 == tmp) {
289  fprintf(stderr, "ERROR, could not find '%x' in shrt\n",
290  shrt_cmpr[i]);
291  err = 1;
292  }
293  shrt_cnvrt[i] = tmp;
294  }
295  tmp = tmp2 = 1;
296  for (i = 0; i < PORT_SHORT; i++) {
297  if (shrt_cnvrt[i] != (i + (nat_shrt - PORT_SHORT)))
298  tmp = 0;
299  if (shrt_cnvrt[i] != (PORT_SHORT - i - 1))
300  tmp2 = 0;
301  }
302  if (tmp)
303  shrt_order = ENDIAN_BIG;
304  else if (tmp2)
305  shrt_order = ENDIAN_LITTLE;
306  else
307  shrt_order = ENDIAN_OTHER;
308 
309  printf("\n/* Native machine byte orders */\n");
310  printf("#define DOUBLE_ORDER %d\n", dbl_order);
311  printf("#define FLOAT_ORDER %d\n", flt_order);
312  printf("#define OFF_T_ORDER %d\n", off_t_order);
313  printf("#define LONG_ORDER %d\n", lng_order);
314  printf("#define INT_ORDER %d\n", int_order);
315  printf("#define SHORT_ORDER %d\n", shrt_order);
316 
317  printf("\n\n/* Translation matrices from big endian to native */\n");
318  dumpflags();
319 
320  return (err);
321 }
322 
323 
324 /*
325  ** match search_value against each char in basis.
326  ** return offset or -1 if not found
327  */
328 static int
329 find_offset(unsigned char *basis, unsigned char search_value, int size)
330 {
331  register int i;
332 
333  for (i = 0; i < size; i++)
334  if (basis[i] == search_value)
335  return (i);
336 
337  return (-1);
338 }
339 
340 
341 static int dumpflags(void)
342 {
343  int i;
344 
345  fprintf(stdout, "\n/* Double format: */\nstatic int dbl_cnvrt[] = {");
346  i = 0;
347  while (i < nat_dbl) {
348  fprintf(stdout, "%d", dbl_cnvrt[i]);
349  if (++i < nat_dbl)
350  fprintf(stdout, ", ");
351  }
352  fprintf(stdout, "};\n\n");
353 
354  fprintf(stdout, "/* Float format : */\nstatic int flt_cnvrt[] = {");
355  i = 0;
356  while (i < nat_flt) {
357  fprintf(stdout, "%d", flt_cnvrt[i]);
358  if (++i < nat_flt)
359  fprintf(stdout, ", ");
360  }
361  fprintf(stdout, "};\n\n");
362 
363  fprintf(stdout, "/* off_t format : */\nstatic int off_t_cnvrt[] = {");
364  i = 0;
365  while (i < nat_off_t) {
366  fprintf(stdout, "%d", off_t_cnvrt[i]);
367  if (++i < nat_off_t)
368  fprintf(stdout, ", ");
369  }
370  fprintf(stdout, "};\n\n");
371 
372  fprintf(stdout, "/* Long format : */\nstatic int lng_cnvrt[] = {");
373  i = 0;
374  while (i < nat_lng) {
375  fprintf(stdout, "%d", lng_cnvrt[i]);
376  if (++i < nat_lng)
377  fprintf(stdout, ", ");
378  }
379  fprintf(stdout, "};\n\n");
380 
381  fprintf(stdout, "/* Int format : */\nstatic int int_cnvrt[] = {");
382  i = 0;
383  while (i < nat_int) {
384  fprintf(stdout, "%d", int_cnvrt[i]);
385  if (++i < nat_int)
386  fprintf(stdout, ", ");
387  }
388  fprintf(stdout, "};\n\n");
389 
390  fprintf(stdout, "/* Short format : */\nstatic int shrt_cnvrt[] = {");
391  i = 0;
392  while (i < nat_shrt) {
393  fprintf(stdout, "%d", shrt_cnvrt[i]);
394  if (++i < nat_shrt)
395  fprintf(stdout, ", ");
396  }
397  fprintf(stdout, "};\n\n");
398 
399  return 0;
400 }
401 
402 /*
403 
404  The 3.0 dig, and dig_plus files are inherently non-portable. This
405  can be seen in moving files between a SUN 386i and other SUN machines.
406  The recommended way to transport files was always to convert to ASCII
407  (b.a.vect) and copy the ASCII files: dig_ascii and dig_att to the
408  destination machine.
409 
410  The problem lies in the way that different architectures internally
411  represent data. If a number is internally store as 0x01020304 on
412  a 680x0 family machine, the same number will be stored as
413  0x04030201 on an 80386 class machine.
414 
415  The CERL port of GRASS to the Compaq 386 already has code to deal
416  with this incompatibility. This code converts all files that are written
417  out to conform to the 680x0 standard. These binary files can then be
418  shared between machines without conversion.
419  This code is designed to work with the majority of computers in use
420  today that fit the following requirements:
421  byte == 8 bits
422  int == 4 bytes
423  long == 4 bytes
424  double == IEEE standard 64 bit
425  float == IEEE standard 32 bit
426  bytes can be swapped around in any reasonable way, but bits within each
427  byte must be maintained in normal high to low ordering: 76543210
428 
429  If this ability is desired on a SUN 386i, for example, you simply
430  define the compiler flag CERL_PORTABLE in the src/CMD/makehead file
431  and recompile all of the mapdev programs.
432 
433 
434  Binary DLG files are NOT supported by this code, and will continue to
435  be non-portable between different architectures.
436 
437 
438  -dave gerdes
439  */
#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
int main(int argc, char **argv)
Definition: port_test.c:106
#define PORT_CHAR
Definition: dig_defines.h:50
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
#define OFF_T_TEST
Definition: port_test.c:61
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 TEST_PATTERN
Definition: port_test.c:59
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)
Definition: symbol/read.c:220
double l
Definition: r_raster.c:39
#define ENDIAN_BIG
Definition: gis.h:381
unsigned char off_t_cnvrt[sizeof(off_t)]
Definition: port_init.c:126
#define INT_TEST
Definition: port_test.c:66
unsigned char dbl_cnvrt[sizeof(double)]
Definition: port_init.c:124
int dbl_order
Definition: port_init.c:117
int nat_shrt
Definition: port_init.c:115
int nat_int
Definition: port_init.c:114
#define SHORT_TEST
Definition: port_test.c:67
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
unsigned char shrt_cnvrt[sizeof(short)]
Definition: port_init.c:129
#define LONG_TEST
Definition: port_test.c:65
#define PORT_INT
Definition: dig_defines.h:48
unsigned char flt_cnvrt[sizeof(float)]
Definition: port_init.c:125