1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /*
18  * Generate a header file (arch.h) with parameters
19  * reflecting the machine architecture and compiler characteristics.
20  */
21 
22 #include "stdpre.h"
23 #include <ctype.h>
24 #include <stdio.h>
25 /*
26  * In theory, not all systems provide <string.h> or declare memset
27  * there, but at this point we don't think we care about any that don't.
28  */
29 #include <string.h>
30 #include <time.h>
31 
32 /* We provide a _SIZEOF_ macro for GX_COLOR_INDEX_TYPE
33    fallback to a generic int if no such type is defined.
34    This default must be kept in sync with the one in gxcindex.h
35    or ARCH_SIZEOF_GX_COLOR_INDEX will be incorrect for such builds. */
36 #ifndef GX_COLOR_INDEX_TYPE
37 #define GX_COLOR_INDEX_TYPE ulong
38 #endif
39 
40 /* We should write the result on stdout, but the original Turbo C 'make' */
41 /* can't handle output redirection (sigh). */
42 
43 static void
section(FILE * f,const char * str)44 section(FILE * f, const char *str)
45 {
46     fprintf(f, "\n\t /* ---------------- %s ---------------- */\n\n", str);
47 }
48 
49 static void
define(FILE * f,const char * str)50 define(FILE *f, const char *str)
51 {
52     fprintf(f, "#define %s ", str);
53 }
54 
55 static void
define_int(FILE * f,const char * str,int value)56 define_int(FILE *f, const char *str, int value)
57 {
58     fprintf(f, "#define %s %d\n", str, value);
59 }
60 
61 static void
print_ffs(FILE * f,int nbytes)62 print_ffs(FILE *f, int nbytes)
63 {
64     int i;
65 
66     for (i = 0; i < nbytes; ++i)
67         fprintf(f, "ff");
68 }
69 
70 static int
ilog2(int n)71 ilog2(int n)
72 {
73     int i = 0, m = n;
74 
75     while (m > 1)
76         ++i, m = (m + 1) >> 1;
77     return i;
78 }
79 
80 static int
copy_existing_file(FILE * f,char * infname)81 copy_existing_file(FILE *f, char *infname)
82 {
83     FILE *in = fopen(infname, "r");
84     char buffer[1024];
85     size_t l;
86 
87     if (in == NULL) {
88         fprintf(stderr, "genarch.c: can't open %s for reading\n", infname);
89         fclose(f);
90         return exit_FAILED;
91     }
92     while (!feof(in)) {
93         l = fread(buffer, 1, 1024, in);
94         if (l > 0)
95             fwrite(buffer, 1, l, f);
96     }
97     fclose(in);
98     fclose(f);
99 
100     return exit_OK;
101 }
102 
103 int
main(int argc,char * argv[])104 main(int argc, char *argv[])
105 {
106     char *fname;
107     long one = 1;
108     struct {
109         char c;
110         short s;
111     } ss;
112     struct {
113         char c;
114         int i;
115     } si;
116     struct {
117         char c;
118         long l;
119     } sl;
120     struct {
121         char c;
122         char *p;
123     } sp;
124     struct {
125         char c;
126         float f;
127     } sf;
128     struct {
129         char c;
130         double d;
131     } sd;
132     struct {
133         char c;
134         size_t z;
135     } sz;
136     long lm1 = -1;
137     long lr1 = lm1 >> 1, lr2 = lm1 >> 2;
138     int im1 = -1;
139     int ir1 = im1 >> 1, ir2 = im1 >> 2;
140     union {
141         long l;
142         char *p;
143     } pl0, pl1;
144     int ars;
145     union {
146         float f;
147         int i;
148         long l;
149     } f0, f1, fm1;
150     int floats_are_IEEE;
151     FILE *f;
152 
153     if (argc < 2 || argc > 3) {
154         fprintf(stderr, "genarch: Invalid invocation\n"
155                 "genarch <output-file> [ <existing-config-file> ]\n");
156         return exit_FAILED;
157     }
158 
159     fname = argv[1];
160     f = fopen(fname, "w");
161     if (f == NULL) {
162         fprintf(stderr, "genarch.c: can't open %s for writing\n", fname);
163         return exit_FAILED;
164     }
165 
166     if (argc == 3) {
167         return copy_existing_file(f, argv[2]);
168     }
169 
170     fprintf(f, "/* Parameters derived from machine and compiler architecture. */\n");
171     fprintf(f, "/* This file is generated mechanically by genarch.c. */\n");
172 
173     /* We have to test the size dynamically here, */
174     /* because the preprocessor can't evaluate sizeof. */
175     f0.f = 0.0, f1.f = 1.0, fm1.f = -1.0;
176     floats_are_IEEE =
177         (size_of(float) == size_of(int) ?
178          f0.i == 0 && f1.i == (int)0x3f800000 && fm1.i == (int)0xbf800000 :
179          f0.l == 0 && f1.l == 0x3f800000L && fm1.l == 0xbf800000L);
180 
181     section(f, "Scalar alignments");
182 
183 #define OFFSET_IN(s, e) (int)((char *)&s.e - (char *)&s)
184     define_int(f, "ARCH_ALIGN_SHORT_MOD", OFFSET_IN(ss, s));
185     define_int(f, "ARCH_ALIGN_INT_MOD", OFFSET_IN(si, i));
186     define_int(f, "ARCH_ALIGN_LONG_MOD", OFFSET_IN(sl, l));
187     define_int(f, "ARCH_ALIGN_SIZE_T_MOD", OFFSET_IN(sz, z));
188 
189 #if defined (GS_MEMPTR_ALIGNMENT) && GS_MEMPTR_ALIGNMENT != 0
190     define_int(f, "ARCH_ALIGN_PTR_MOD", GS_MEMPTR_ALIGNMENT);
191 #else
192 #if defined (sparc) || defined (__hpux)
193 # ifndef __BIGGEST_ALIGNMENT__
194 #  define __BIGGEST_ALIGNMENT__ 8
195 # endif
196     define_int(f, "ARCH_ALIGN_PTR_MOD", __BIGGEST_ALIGNMENT__);
197 #else
198     define_int(f, "ARCH_ALIGN_PTR_MOD", OFFSET_IN(sp, p));
199 #endif
200 #endif
201 
202     define_int(f, "ARCH_ALIGN_FLOAT_MOD", OFFSET_IN(sf, f));
203     define_int(f, "ARCH_ALIGN_DOUBLE_MOD", OFFSET_IN(sd, d));
204 #undef OFFSET_IN
205 
206     /* Some architectures have special alignment requirements for   */
207     /* jmp_buf, and we used to provide ALIGN_STRUCT_MOD for that.   */
208     /* We've now dropped that in favor of aligning jmp_buf by hand. */
209     /* See setjmp_.h for the implementation of this.                */
210 
211     section(f, "Scalar sizes");
212 
213     define_int(f, "ARCH_LOG2_SIZEOF_CHAR", ilog2(size_of(char)));
214     define_int(f, "ARCH_LOG2_SIZEOF_SHORT", ilog2(size_of(short)));
215     define_int(f, "ARCH_LOG2_SIZEOF_INT", ilog2(size_of(int)));
216     define_int(f, "ARCH_LOG2_SIZEOF_LONG", ilog2(size_of(long)));
217     define_int(f, "ARCH_LOG2_SIZEOF_SIZE_T", ilog2(size_of(size_t)));
218 #if !defined(_MSC_VER) && ! (defined(__BORLANDC__) && defined(__WIN32__))
219     /* MSVC does not provide 'long long' but we need this on some archs
220        to define a 64 bit type. A corresponding #ifdef in stdint_.h handles
221        that case for MSVC. Most other platforms do support long long if
222        they have a 64 bit type at all */
223     define_int(f, "ARCH_LOG2_SIZEOF_LONG_LONG", ilog2(size_of(long long)));
224 #endif
225     define_int(f, "ARCH_SIZEOF_SIZE_T", size_of(size_t));
226     define_int(f, "ARCH_SIZEOF_GX_COLOR_INDEX", sizeof(GX_COLOR_INDEX_TYPE));
227     define_int(f, "ARCH_SIZEOF_PTR", size_of(char *));
228     define_int(f, "ARCH_SIZEOF_FLOAT", size_of(float));
229     define_int(f, "ARCH_SIZEOF_DOUBLE", size_of(double));
230     if (floats_are_IEEE) {
231         define_int(f, "ARCH_FLOAT_MANTISSA_BITS", 24);
232         define_int(f, "ARCH_DOUBLE_MANTISSA_BITS", 53);
233     } else {
234         /*
235          * There isn't any general way to compute the number of mantissa
236          * bits accurately, especially if the machine uses hex rather
237          * than binary exponents.  Use conservative values, assuming
238          * the exponent is stored in a 16-bit word of its own.
239          */
240         define_int(f, "ARCH_FLOAT_MANTISSA_BITS", sizeof(float) * 8 - 17);
241         define_int(f, "ARCH_DOUBLE_MANTISSA_BITS", sizeof(double) * 8 - 17);
242     }
243 
244     section(f, "Unsigned max values");
245 
246     /*
247      * We can't use fprintf with a numeric value for PRINT_MAX, because
248      * too many compilers produce warnings or do the wrong thing for
249      * complementing or widening unsigned types.
250      */
251 #define PRINT_MAX(str, typ, tstr, l)\
252   BEGIN\
253     define(f, str);\
254     fprintf(f, "((%s)0x", tstr);\
255     print_ffs(f, sizeof(typ));\
256     fprintf(f, "%s + (%s)0)\n", l, tstr);\
257   END
258     PRINT_MAX("ARCH_MAX_UCHAR", unsigned char, "unsigned char", "");
259     PRINT_MAX("ARCH_MAX_USHORT", unsigned short, "unsigned short", "");
260     /*
261      * For uint and ulong, a different approach is required to keep gcc
262      * with -Wtraditional from spewing out pointless warnings.
263      */
264     define(f, "ARCH_MAX_UINT");
265     fprintf(f, "((unsigned int)~0 + (unsigned int)0)\n");
266     define(f, "ARCH_MAX_ULONG");
267     fprintf(f, "((unsigned long)~0L + (unsigned long)0)\n");
268     define(f, "ARCH_MAX_SIZE_T");
269     fprintf(f, "((size_t)~0L + (size_t)0)\n");
270 #undef PRINT_MAX
271 
272     section(f, "Miscellaneous");
273 
274     define_int(f, "ARCH_IS_BIG_ENDIAN", 1 - *(char *)&one);
275     pl0.l = 0;
276     pl1.l = -1;
277     define_int(f, "ARCH_PTRS_ARE_SIGNED", (pl1.p < pl0.p));
278     define_int(f, "ARCH_FLOATS_ARE_IEEE", (floats_are_IEEE ? 1 : 0));
279 
280     /*
281      * There are three cases for arithmetic right shift:
282      * always correct, correct except for right-shifting a long by 1
283      * (a bug in some versions of the Turbo C compiler), and
284      * never correct.
285      */
286     ars = (lr2 != -1 || ir1 != -1 || ir2 != -1 ? 0 :
287            lr1 != -1 ? 1 :	/* Turbo C problem */
288            2);
289     define_int(f, "ARCH_ARITH_RSHIFT", ars);
290     /*
291      * Determine whether dividing a negative integer by a positive one
292      * takes the floor or truncates toward zero.
293      */
294     define_int(f, "ARCH_DIV_NEG_POS_TRUNCATES", im1 / 2 == 0);
295 
296 /* ---------------- Done. ---------------- */
297 
298     fclose(f);
299     return exit_OK;
300 }
301