GRASS 8 Programmer's Manual 8.6.0dev(2026)-1d1e47ad9d
Loading...
Searching...
No Matches
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
92static double u_d = TEST_PATTERN;
93static float u_f = TEST_PATTERN;
94off_t u_o; /* depends on sizeof(off_t) */
95static long u_l = LONG_TEST;
96static int u_i = INT_TEST;
97static short u_s = SHORT_TEST;
98
99/* dbl_cmpr holds the bytes of an IEEE representation of TEST_PATTERN */
100static const unsigned char dbl_cmpr[] = {0x3f, 0xf5, 0x55, 0x32,
101 0x61, 0x7c, 0x1b, 0xda};
102/* flt_cmpr holds the bytes of an IEEE representation of TEST_PATTERN */
103static const unsigned char flt_cmpr[] = {0x3f, 0xaa, 0xa9, 0x93};
104static const unsigned char off_t_cmpr[] = {0x01, 0x02, 0x03, 0x04,
105 0x05, 0x06, 0x07, 0x08};
106static const unsigned char lng_cmpr[] = {0x01, 0x02, 0x03, 0x04};
107static const unsigned char int_cmpr[] = {0x01, 0x02, 0x03, 0x04};
108static const unsigned char shrt_cmpr[] = {0x01, 0x02};
109
110/* Find native sizes */
111int nat_dbl = sizeof(double);
112int nat_flt = sizeof(float);
113int nat_off_t = sizeof(off_t);
114int nat_lng = sizeof(long);
115int nat_int = sizeof(int);
116int nat_shrt = sizeof(short);
117
124
125unsigned char dbl_cnvrt[sizeof(double)];
126unsigned char flt_cnvrt[sizeof(float)];
127unsigned char off_t_cnvrt[sizeof(off_t)];
128unsigned char lng_cnvrt[sizeof(long)];
129unsigned char int_cnvrt[sizeof(int)];
130unsigned char shrt_cnvrt[sizeof(short)];
131
132/*
133 * match search_value against each char in basis.
134 * return offset or -1 if not found
135 */
136static int find_offset(const unsigned char *basis, unsigned char search_value,
137 int size)
138{
139 int i;
140
141 for (i = 0; i < size; i++)
142 if (basis[i] == search_value)
143 return (i);
144
145 return (-1);
146}
147
148static int find_offsets(const void *pattern, unsigned char *cnvrt,
149 const unsigned char *cmpr, int port_size, int nat_size,
150 const char *typename)
151{
152 int big, ltl;
153 int i;
154
155 for (i = 0; i < port_size; i++) {
156 int off = find_offset(pattern, cmpr[i], nat_size);
157
158 if (off < 0)
159 G_fatal_error(_("Unable to find '%x' in %s"), cmpr[i], typename);
160
161 cnvrt[i] = off;
162 }
163
164 big = ltl = 1;
165
166 for (i = 0; i < port_size; i++) {
167 if (cnvrt[i] != (nat_size - port_size + i))
168 big = 0; /* isn't big endian */
169 if (cnvrt[i] != (port_size - 1 - i))
170 ltl = 0; /* isn't little endian */
171 }
172
173 if (big)
174 return ENDIAN_BIG;
175
176 if (ltl)
177 return ENDIAN_LITTLE;
178
179 return ENDIAN_OTHER;
180}
181
182/*!
183 \brief Initialize Port_info structures
184 */
185void port_init(void)
186{
187 static int done;
188
189 if (done)
190 return;
191
192 done = 1;
193
194 /* Following code checks only if all assumptions are fulfilled */
195 /* Check sizes */
196 if (nat_dbl != PORT_DOUBLE)
197 G_fatal_error("sizeof(double) != %d", PORT_DOUBLE);
198 if (nat_flt != PORT_FLOAT)
199 G_fatal_error("sizeof(float) != %d", PORT_DOUBLE);
200 /* off_t size is variable, depending on the vector size and LFS support */
201 if (nat_lng < PORT_LONG)
202 G_fatal_error("sizeof(long) < %d", PORT_LONG);
203 if (nat_int < PORT_INT)
204 G_fatal_error("sizeof(int) < %d", PORT_INT);
205 if (nat_shrt < PORT_SHORT)
206 G_fatal_error("sizeof(short) < %d", PORT_SHORT);
207
208 /* Find for each byte in big endian test pattern (*_cmpr)
209 * offset of corresponding byte in machine native order.
210 * Look if native byte order is little or big or some other (pdp)
211 * endian.
212 */
213
214 if (nat_off_t == 8)
215#ifdef HAVE_LONG_LONG_INT
217#else
218 G_fatal_error("Internal error: can't construct an off_t literal");
219#endif
220 else
222
223 dbl_order =
224 find_offsets(&u_d, dbl_cnvrt, dbl_cmpr, PORT_DOUBLE, nat_dbl, "double");
225 flt_order =
226 find_offsets(&u_f, flt_cnvrt, flt_cmpr, PORT_FLOAT, nat_flt, "float");
227 off_t_order = find_offsets(&u_o, off_t_cnvrt, off_t_cmpr, nat_off_t,
228 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 = find_offsets(&u_s, shrt_cnvrt, shrt_cmpr, PORT_SHORT, nat_shrt,
234 "short");
235}
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
#define PORT_LONG
Definition dig_defines.h:47
#define PORT_SHORT
Definition dig_defines.h:49
#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 PORT_FLOAT
Definition dig_defines.h:46
#define PORT_INT
Definition dig_defines.h:48
#define ENDIAN_OTHER
Definition gis.h:417
#define ENDIAN_LITTLE
Endian check.
Definition gis.h:415
#define ENDIAN_BIG
Definition gis.h:416
#define _(str)
Definition glocale.h:10
unsigned char flt_cnvrt[sizeof(float)]
Definition port_init.c:126
off_t u_o
Definition port_init.c:94
int nat_lng
Definition port_init.c:114
int shrt_order
Definition port_init.c:123
#define LONG_TEST
Definition port_init.c:88
unsigned char dbl_cnvrt[sizeof(double)]
Definition port_init.c:125
int flt_order
Definition port_init.c:119
int dbl_order
Definition port_init.c:118
int int_order
Definition port_init.c:122
int nat_dbl
Definition port_init.c:111
#define TEST_PATTERN
Definition port_init.c:84
unsigned char lng_cnvrt[sizeof(long)]
Definition port_init.c:128
int off_t_order
Definition port_init.c:120
int lng_order
Definition port_init.c:121
unsigned char off_t_cnvrt[sizeof(off_t)]
Definition port_init.c:127
#define INT_TEST
Definition port_init.c:89
int nat_off_t
Definition port_init.c:113
#define LONG_LONG_TEST
Definition port_init.c:86
int nat_shrt
Definition port_init.c:116
int nat_int
Definition port_init.c:115
#define SHORT_TEST
Definition port_init.c:90
unsigned char shrt_cnvrt[sizeof(short)]
Definition port_init.c:130
void port_init(void)
Initialize Port_info structures.
Definition port_init.c:185
unsigned char int_cnvrt[sizeof(int)]
Definition port_init.c:129
int nat_flt
Definition port_init.c:112