1/** @file
2    Every thing you wanted to know about your compiler but didn't know whom to ask.
3
4    COPYRIGHT(c) 1993-9 Steven Pemberton, CWI. All rights reserved.
5    Steven Pemberton, CWI, Amsterdam; "Steven.Pemberton@cwi.nl"
6    Used with permission.
7
8    Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
9    This program and the accompanying materials
10    are licensed and made available under the terms and conditions of the BSD License
11    which accompanies this distribution. The full text of the license may be found at
12    http://opensource.org/licenses/bsd-license.
13
14    THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15    WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16**/
17#if defined(_MSC_VER)           /* Handle Microsoft VC++ compiler specifics. */
18  #pragma warning ( disable : 4018 )
19  #pragma warning ( disable : 4055 )
20  #pragma warning ( disable : 4116 )
21  #pragma warning ( disable : 4130 )
22  #pragma warning ( disable : 4189 )
23  #pragma warning ( disable : 4244 )
24  #pragma warning ( disable : 4723 )
25#endif  /* defined(_MSC_VER) */
26
27//#define NO_SC   1   // Compiler doesn't support signed char
28//#define NO_UC   1   // Compiler doesn't support unsigned char
29//#define NO_UI   1   // Compiler doesn't support unsigned short and long
30//#define NO_VOID 1   // Compiler doesn't support void
31//#define NO_SIG  1   // Compiler doesn't support signal() or setjmp/longjmp()
32
33/*  Some compilers can't cope with "#ifdef __FILE__". Use
34    either the FILENAME or BAD_CPP macro as described below.
35*/
36/*  If your C preprocessor doesn't have the predefined __FILE__
37macro, and you don't want to call this file enquire.c but, say,
38tell.c, uncomment the following and change enquire.c to tell.c.
39*/
40//#define FILENAME "enquire.c"
41
42/*  Some compilers won't accept the line "#include FILENAME".  Uncomment
43    the following macro. In that case, this file *must* be called enquire.c.
44*/
45//#define BAD_CPP     1
46
47/*  Some naughty compilers define __STDC__, but don't really
48    support it.  Some define it as 0, in which case we ignore it.
49    But if your compiler defines it, and isn't really ANSI C,
50    uncomment the BAD_STDC macro. (To those compiler writers: for shame).
51*/
52//#define BAD_STDC    1
53
54/*  Some naughty compilers define __STDC__, but don't have the
55    stddef.h include file. Uncomment the BAD_STDDEF macro. (Gcc needs this on
56    some machines, due to clashes between stddef.h and other include files.)
57*/
58//#define BAD_STDDEF  1
59
60/*  Some systems crash when you try to malloc all store. To save users of such
61    defective systems too much grief, they may uncomment the BAD_MALLOC macro,
62    which ignores that bit of the code.
63*/
64//#define BAD_MALLOC  1
65
66
67
68#ifndef PROGRAM
69#define PROGRAM enquire.c
70#define VERSION "5.1a"
71#define PURPOSE Everything you wanted to know about your machine and C compiler
72#define BUT didnt know who to ask
73#define FOR Any OS, any C compiler
74#define AUTHOR  Steven Pemberton, CWI, Amsterdam; "Steven.Pemberton@cwi.nl"
75#define COPYRIGHT(c) 1993-9 Steven Pemberton, CWI. All rights reserved.
76#define NOTE  Improvements gratefully received. Please mention the version.
77#define COMPILE On Unix compile with: "sh enquire.c"; see below for details
78#define WEB "http://www.cwi.nl/~steven/enquire.html"
79#endif
80
81#ifdef NOTDEFINED /* This is how you compile it; see below for details */
82  case $0 in
83  *.c) ;;
84  sh) echo 'Use "sh enquire.c", not "sh < enquire.c"' >&2; exit 1;;
85  *) echo 'Filename must end in ".c"' >&2; exit 1;;
86  esac
87  if test -r test.c
88  then echo Would overwrite test.c - try it somewhere safer >&2; exit 1
89  fi
90  CFLAGS=
91  echo Testing for needed CFLAGS ...
92  echo "main(){char c; c=0;}" > test.c
93  if ${CC=cc} ${1+"$@"} -o enquire test.c $LIBS
94  then :
95  else
96      echo '*** "'$CC ${1+"$@"} -o enquire test.c $LIBS'" failed'
97      echo '*** Giving up'
98      /bin/rm -f test.c
99      exit 1
100  fi
101  echo "main(){signed char c; c=0;}" > test.c
102  if $CC ${1+"$@"} -o enquire test.c $LIBS 2>/dev/null
103  then echo "   Signed char ok"
104  else
105    CFLAGS=-DNO_SC
106    echo "   Signed char not accepted; using $CFLAGS"
107  fi
108  echo "main(){unsigned char c; c=0;}" > test.c
109  if $CC ${1+"$@"} -o enquire test.c $LIBS 2>/dev/null
110  then echo "   Unsigned char ok"
111  else
112    CFLAGS="$CFLAGS -DNO_UC"
113    echo "   Unsigned char not accepted; using $CFLAGS"
114  fi
115  echo "main(){unsigned short s;unsigned long l;s=0;l=0;}" > test.c
116  if $CC ${1+"$@"} -o enquire test.c $LIBS 2>/dev/null
117  then echo "   Unsigned short and long ok"
118  else
119    CFLAGS="$CFLAGS -DNO_UI"
120    echo "   Unsigned short or long not accepted; using $CFLAGS"
121  fi
122  echo "void foo(){} main(){foo();}" > test.c
123  if $CC ${1+"$@"} -o enquire test.c $LIBS 2>/dev/null
124  then echo "   Void ok"
125  else
126    CFLAGS="$CFLAGS -DNO_VOID"
127    echo "   Void not accepted; using $CFLAGS"
128  fi
129  /bin/rm -f test.c a.out
130
131  echo Compiling $0 ...
132  case $# in
133  0) : check bug in interpreting "$@" in some shells, if no parameters
134     case `echo 1 "$@" 2` in
135     "1  2") echo '   *** There is a bug in your shell expanding "$@"!'
136       echo '   *** Taking remedial action' ;;
137     "1 2") ;;
138     esac
139  esac
140  case $ID in
141  "") echo "   $CC" $CFLAGS "$@" $0 -o enquire $LIBS
142      $CC $CFLAGS ${1+"$@"} $0 -o enquire $LIBS ||
143    { echo '***' Try setting some CFLAGS; exit 1; }
144      ;;
145  *)  echo "   $CC" $CFLAGS "$@" -DID="\"$ID\"" $0 -o enquire $LIBS
146      $CC $CFLAGS ${1+"$@"} -DID="\"$ID\"" $0 -o enquire $LIBS ||
147    { echo '***' Try setting some CFLAGS; exit 1; }
148  esac
149  echo "Producing enquire.out limits.h and float.h ..."
150  echo "   enquire > enquire.out"
151  ./enquire > enquire.out || echo '   *** Some problems: see enquire.out'
152  echo "   enquire -l > limits.h"
153  ./enquire -l > limits.h || echo '   *** Some problems: see limits.h'
154  echo "   enquire -f > float.h"
155  ./enquire -f > float.h  || echo '   *** Some problems: see float.h'
156  echo "Verifying the contents of limits.h and float.h ..."
157  echo "   $CC" -DVERIFY $CFLAGS "$@" $0 -o verify $LIBS
158  $CC -DVERIFY $CFLAGS ${@+"$@"} $0 -o verify $LIBS ||
159    { echo '***' Failed; exit 1; }
160  echo "   verify -fl > verify.out"
161  ./verify -fl > verify.out ||
162    echo '   *** Some problems: see verify.out'
163  echo Done
164  exit 0
165#endif
166
167/*
168 PURPOSE
169    This is a program that determines many properties of the C
170    compiler and machine that it is run on, such as minimum and
171    maximum [un]signed char/int/long, many properties of float/ [long]
172    double, and so on.
173
174    As an option it produces the ANSI C float.h and limits.h files.
175
176    As a further option, it even checks that the compiler reads the
177    header files correctly.
178
179    It is a good test-case for compilers, since it exercises them with
180    many limiting values, such as the minimum and maximum floating-point
181    numbers.
182
183 COMPILING AND RUNNING ON UNIX MACHINES
184    With luck and a following wind, on Unix systems just the following
185    will work:
186  sh enquire.c    (or whatever filename you chose).
187    Any parameters are passed to the C compiler, so if the compilation
188    fails for any reason curable as explained below, you can do the following:
189  sh enquire.c -DBAD_CPP
190
191    If you do get compilation errors, check the line in question.
192    Very often there is a comment attached saying which define to set.
193
194    You can use a different C compiler than the default cc by setting CC:
195  CC=gcc sh enquire.c -ansi
196    You can load extra libraries by setting LIBS:
197  CC=gcc LIBS=-lflong sh enquire.c -ansi
198    Add ID="string" for the string to be added to the output; for instance:
199  ID="`hostname` cc -ansi" sh enquire.c -ansi
200
201    Compiling may give messages about unreachable code. These you can ignore.
202
203    Some compilers offer various flags for different floating point
204    modes; it's worth trying all possible combinations of these.
205
206    Don't say I haven't tried to make life easy for you...
207
208 COMPILING AND RUNNING ON NON-UNIX SYSTEMS
209    On non-Unix systems, you must say (the equivalent of):
210  cc enquire.c -o enquire
211  enquire > enquire.out
212  enquire -l > limits.h
213  enquire -f > float.h
214  cc -DVERIFY enquire.c -o verify #this includes limits.h and float.h
215  verify -fl > verify.out
216
217    If your compiler doesn't support:   add flag:
218  signed char (eg pcc)      -DNO_SC
219  unsigned char       -DNO_UC
220  unsigned short and long     -DNO_UI
221  void          -DNO_VOID
222  signal(), or setjmp/longjmp()   -DNO_SIG
223
224    Try to compile first with no flags, and see if you get any errors
225    - you might be surprised. (Most non-ANSI compilers need -DNO_SC,
226    though.)  Some compilers need a -f flag for floating point.
227
228    Don't use any optimisation flags: the program may not work if you
229    do.  Though "while (a+1.0-a-1.0 == 0.0)" may look like "while(1)"
230    to an optimiser, to a floating-point unit there's a world of difference.
231
232    Compiling may give messages about unreachable code. These you can ignore.
233
234    Some compilers offer various flags for different floating point
235    modes; it's worth trying all possible combinations of these.
236
237 FAULTY COMPILERS
238    Because of bugs and/or inadequacies, some compilers need the following
239    defines:
240
241    -  If your C preprocessor doesn't have the predefined __FILE__
242       macro, and you don't want to call this file enquire.c but, say,
243       tell.c, add the flag -DFILENAME=\"tell.c\" .
244
245    -  Some compilers won't accept the line "#include FILENAME".  Add
246       flag -DBAD_CPP. In that case, this file *must* be called
247       enquire.c.
248
249    -  Some compilers can't cope with "#ifdef __FILE__". Use
250       -DFILENAME= or -DBAD_CPP as above.
251
252    -  Some naughty compilers define __STDC__, but don't really
253       support it.  Some define it as 0, in which case we ignore it.
254       But if your compiler defines it, and isn't really ANSI C, add
255       flag -DBAD_STDC. (To those compiler writers: for shame).
256
257    -  Some naughty compilers define __STDC__, but don't have the
258       stddef.h include file. Add flag -DBAD_STDDEF. (Gcc needs this
259       on some machines, due to clashes between stddef.h and other
260       include files.)
261
262    -  Some systems crash when you try to malloc all store. To save
263       users of such defective systems too much grief, they may
264       compile with -DBAD_MALLOC, which ignores that bit of the code.
265
266    Summary of naughty-compiler flags:
267    If your compiler doesn't support:    add flag:
268  __FILE__ (and you changed the filename) -DFILENAME=\"name.c\"
269  #ifdef __FILE__       -DBAD_CPP or -DFILENAME=...
270  #include FILENAME     -DBAD_CPP
271  __STDC__ (properly)     -DBAD_STDC
272  stddef.h        -DBAD_STDDEF
273  malloc(LOTS) == NULL      -DBAD_MALLOC
274
275    While it is not our policy to support defective compilers, pity has been
276    taken on people with compilers that can't produce object files bigger than
277    32k (especially since it was an easy addition). Compile the program
278    into separate parts like this:
279  cc -c -DSEP -DPASS0 -o p0.o <other flags> enquire.c
280  cc -c -DSEP -DPASS1 -o p1.o <other flags> enquire.c
281  cc -c -DSEP -DPASS2 -o p2.o <other flags> enquire.c
282  cc -c -DSEP -DPASS3 -o p3.o <other flags> enquire.c
283  cc -o enquire p0.o p1.o p2.o p3.o
284
285 SYSTEM DEPENDENCIES
286    You may possibly need to add some calls to signal() for other sorts of
287    exception on your machine than SIGFPE, SIGOVER, SIGBUS, and SIGSEGV.
288    See lines beginning #ifdef SIGxxx (and communicate the differences to me!).
289
290 OUTPUT
291    Running without argument gives the information as English text. If run
292    with argument -l (e.g. enquire -l), output is a series of #define's for
293    the ANSI standard limits.h include file, excluding MB_MAX_CHAR. If run
294    with argument -f, output is a series of #define's for the ANSI standard
295    float.h include file (according to ANSI C Draft of Dec 7, 1988).
296    Flag -v gives verbose output: output includes the English text above
297    as C comments. The program exit(0)'s if everything went ok, otherwise
298    it exits with a positive number, telling how many problems there were.
299
300 VERIFYING THE COMPILER
301    If, having produced the float.h and limits.h header files, you want to
302    verify that the compiler reads them back correctly (there are a lot of
303    boundary cases, of course, like minimum and maximum numbers), you can
304    recompile enquire.c with -DVERIFY set (plus the other flags that you used
305    when compiling the version that produced the header files). This then
306    recompiles the program so that it #includes "limits.h" and "float.h",
307    and checks that the constants it finds there are the same as the
308    constants it produces. Run the resulting program with enquire -fl.
309    Many compilers fail this test.
310    NB: You *must* recompile with the same compiler and flags, otherwise
311    you may get odd results.
312
313    You can also use this option if your compiler already has both files,
314    and you want to confirm that this program produces the right results.
315
316 TROUBLESHOOTING.
317    This program is now quite trustworthy, and suspicious and wrong output
318    may well be caused by bugs in the compiler, not in the program (however
319    of course, this is not guaranteed, and no responsibility can be
320    accepted, etc.)
321
322    The program only works if overflows are ignored by the C system or
323    are catchable with signal().
324
325    If the program fails to run to completion (often with the error message
326    "Unexpected signal at point x"), this often turns out to be a bug in the
327    C compiler's run-time system. Check what was about to be printed, and
328    try to narrow the problem down.
329
330    Another possible problem is that you have compiled the program to produce
331    loss-of-precision arithmetic traps. The program cannot cope with these,
332    and you should re-compile without them. (They should never be the default).
333
334    Make sure you compiled with optimisation turned off.
335
336    Output preceded by *** WARNING: identifies behaviour of the C system
337    deemed incorrect by the program. Likely problems are that printf or
338    scanf don't cope properly with certain boundary numbers: this program
339    goes to a lot of trouble to calculate its values, and these values
340    are mostly boundary numbers. Experience has shown that often printf
341    cannot cope with these values, and so in an attempt to increase
342    confidence in the output, for each float and double that is printed,
343    the printed value is checked by using sscanf to read it back.
344   Care is taken that numbers are printed with enough digits to uniquely
345    identify them, and therefore that they can be read back identically.
346    If the number read back is different, then there is probably a bug in
347    printf or sscanf, and the program prints the warning message.
348    If the two numbers in the warning look identical, then printf is more
349    than likely rounding the last digit(s) incorrectly. To put you at ease
350    that the two really are different, the bit patterns of the two numbers
351    are also printed. The difference is very likely in the last bit.
352   Many scanf's read the minimum double back as 0.0, and similarly cause
353    overflow when reading the maximum double. This program quite ruthlessly
354    declares all these behaviours faulty. The point is that if you get
355    one of these warnings, the output may be wrong, so you should check
356    the result carefully if you intend to use the results. Of course, printf
357    and sscanf may both be wrong, and cancel each other out, so you should
358    check the output carefully anyway.
359
360    The warning that "a cast didn't work" refers to cases like this:
361
362  float f;
363  #define C 1.234567890123456789
364  f= C;
365  if (f != (float) C) printf ("Wrong!");
366
367    A faulty compiler will widen f to double and ignore the cast to float,
368    and because there is more accuracy in a double than a float, fail to
369    recognise that they are the same. In the actual case in point, f and C
370    are passed as parameters to a function that discovers they are not equal,
371    so it's just possible that the error was in the parameter passing,
372    not in the cast (see function Verify()).
373    For ANSI C, which has float constants, the error message is "constant has
374    wrong precision".
375
376 REPORTING PROBLEMS
377    If the program doesn't work for you for any reason that can't be
378    narrowed down to a problem in the C compiler, or it has to be
379    changed in order to get it to compile, or it produces suspicious
380    output (like a very low maximum float, for instance), please mail
381    the problem and an example of the incorrect output to
382    Steven.Pemberton@cwi.nl so that improvements can be worked into
383    future versions. Try to give as much information as possible;
384    DON'T FORGET TO MENTION THE VERSION NUMBER!
385
386    The program tries to catch and diagnose bugs in the compiler/run-time
387    system. I would be especially pleased to have reports of failures so
388    that I can improve this service.
389
390    I apologise unreservedly for the contorted use of the preprocessor...
391    but it was fun!
392
393 NEW VERSIONS
394    Worried that you may not have the latest version? Ftp to
395    ftp.cwi.nl, and look in directory pub/steven/enquire
396    for file enquireXX.c; XX is the version number. Or look at
397    http://www.cwi.nl/~steven/enquire.html
398
399 HOW DOES ENQUIRE WORK?
400    There is an article that explains a lot of the workings: The
401    Ergonomics of Portability; available from the above addresses as file
402    enquire.ps.
403
404 THE SMALL PRINT
405    This is not a public domain program; nor is any other program that
406    carries a copyright notice. It is however freely copyable under the
407    following conditions:
408
409       You may copy and distribute verbatim copies of this source file.
410       You may modify this source file, and copy and distribute such
411       modified versions, provided that you leave the copyright notice
412       at the top of the file and also cause the modified file to carry
413       prominent notices stating that you changed the files and the
414       date of any change; and cause the whole of any work that you
415       distribute or publish, that in whole or in part contains or is a
416       derivative of this program or any part thereof, to be licensed
417       at no charge to all third parties on terms identical to those
418       here.
419
420    While every effort has been taken to make this program as reliable as
421    possible, no responsibility can be taken for the correctness of the
422    output, nor suitability for any particular use.
423
424    If you do have a fix to any problem, please send it to me, so that
425    other people can have the benefits.
426
427    This program is an offshoot of a project funded by public funds.
428    If you use this program for research or commercial use (i.e. more
429    than just for the fun of knowing about your compiler) mailing a short
430    note of acknowledgement may help keep enquire.c supported.
431
432 ACKNOWLEDGEMENTS
433    Many people have given time and ideas to making this program what it is.
434    To all of them thanks, and apologies for not mentioning them by name.
435
436 HISTORY
437    Originally started as a program to generate configuration constants
438    for a large piece of software we were writing, which later took on
439    a life of its own...
440    1.0 Length 6658!; end 1984?
441  Unix only. Only printed a dozen maximum int/double values.
442    2.0 Length 10535; Spring 1985
443  Prints values as #defines (about 20 of them)
444  More extensive floating point, using Cody and Waite
445  Handles signals better
446  Programs around optimisations
447  Handles Cybers
448    3.0 Length 12648; Aug 1987; prints about 42 values
449  Added PASS stuff, so treats float as well as double
450    4.0 Length 33891; Feb 1989; prints around 85 values
451  First GNU version (for gcc, where they called it hard-params.c)
452  Generates float.h and limits.h files
453  Handles long double
454  Generates warnings for dubious output
455    4.1 Length 47738; April 1989
456  Added VERIFY and TEST
457    4.2 Length 63442; Feb 1990
458  Added SEP
459  Fixed eps/epsneg
460  Added check for pseudo-unsigned chars
461  Added description for each #define output
462  Added check for absence of defines during verify
463  Added prototypes
464  Added BAD_STDC and BAD_CPP
465  Fixed alignments output
466    4.3 Length 75000; Oct 1990; around 114 lines of output
467  Function xmalloc defined, Richard Stallman, June 89.
468  Alignments computed from member offsets rather than structure sizes,
469      Richard Stallman, Oct 89
470  Print whether char* and int* pointers have the same format;
471      also char * and function *
472  Update to Draft C version Dec 7, 1988
473      - types of constants produced in limits.h
474    (whether to put a U after unsigned shorts and chars and
475     whether to output -1024 as (-1023-1))
476      - values of SCHAR_MIN/MAX
477      - values of *_EPSILON (not the smallest but the effective smallest)
478  Added FILENAME, since ANSI C doesn't allow #define __FILE__
479  Renamed from config.c to enquire.c
480  Added size_t and ptrdiff_t enquiries
481  Added promotion enquiries
482  Added type checks of #defines
483  Added BAD_STDDEF
484  Changed endian to allow for cases where not all bits are used
485  Sanity check for max integrals
486  Fixed definition of setjmp for -DNO_SIG
487  Moved #define ... 0.0L inside #ifdef STDC, in case some cpp's tokenize
488  Added BAD_MALLOC
489    5.0 Length 88228; February 1993; around 120 lines of output
490         (depends on what you count)
491  Added the 'sh enquire.c' horror/delight: thanks David Mankins@think
492  Added checks for long names: thanks Steve Simon@leeds-poly
493  Added FPE signal checks: thanks Leonid A. Broukhis
494  Added check for dereferencing NULL
495  Added TESTI
496  Added LIBS, fixed showtype: thanks Rainer Orth@TechFak.Uni-Bielefeld.DE
497  Added a free(): thanks nickc@perihelion.co.uk
498  Added signal catching to the malloc part
499  Renamed naughty-compiler defines to BAD_*
500  Renamed and altered Verify() to better check faulty compilers
501  Shut some compilers up from giving incorrect warnings.
502  Fixed sign_of(): thanks Hugh Redelmeier@redvax
503  Fixed USHRT_MAX for sizeof(short)=sizeof(int) but INT_MAX > SHRT_MAX
504  Fixed NO_UI
505  Fixed -DSEP: thanks Mike Black@seismo
506  Fixed the case where stdio.h includes limits.h: thanks rms@gnu
507  Fixed exponent(): thanks Christophe BINOT
508    <chb%hpvpta.france.hp.com@hplb.hpl.hp.com>
509   5.0a Aug 1997
510  Made handling of ID= easier
511  Improved the reporting of use of bits in Floating values.
512   5.1  Length 88739; Sep 1998
513  Fixed detection of infinity for machines with no overflow trap
514  Speeded up search for max char (first 32 bit char machine turned up...)
515   5.1a Length 88832; Feb 1999
516  Changed identification message
517   5.1b Length 88926; Oct 2002
518        Fixed a missing \n in an output line; thanks Leonid Broukhis again
519*/
520
521/* Set FILENAME to the name of this file */
522#ifndef FILENAME
523#ifdef BAD_CPP
524#define FILENAME "enquire.c"
525#else
526#ifdef __FILE__ /* It's a compiler bug if this fails. Define BAD_CPP */
527#define FILENAME __FILE__
528#else
529#define FILENAME "enquire.c"
530#endif /* __FILE__ */
531#endif /* BAD_CPP */
532#endif /* FILENAME */
533
534/* This file is read three times (it #includes itself), to generate
535   otherwise identical code for each of short+float, int+double,
536   long+long double. If PASS isn't defined, then this is the first pass.
537   Code bracketed by 'PASS0' is for stuff independent of all three,
538   but is read during the first pass.
539*/
540#ifndef PASS
541#ifdef SEP /* so we're only interested if this is pass 1 or not */
542#ifdef PASS1
543#define PASS 1
544#else
545#define PASS 0
546#endif
547#else /* no SEP, so this is the first pass */
548#define PASS 1
549#define PASS0 1
550#define PASS1 1
551#endif /* SEP */
552
553/* Void just marks the functions that don't return a result */
554#ifdef NO_VOID
555#define Void int
556#else
557#define Void void
558#endif
559
560/* Set STDC to whether this is *really* an ANSI C compiler.
561   Some bad compilers define __STDC__, when they don't support it.
562   Compile with -DBAD_STDC to get round this.
563*/
564#ifndef BAD_STDC
565#ifdef __STDC__
566#if __STDC__ /* If __STDC__ is 0, assume it isn't supported */
567#define STDC
568#endif
569#endif
570#endif
571
572/* Stuff different for ANSI C, and old C:
573   ARGS and NOARGS are used for function prototypes.
574   Volatile is used to reduce the chance of optimisation,
575  and to prevent variables being put in registers (when setjmp/longjmp
576  wouldn't work as we want)
577   Long_double is the longest floating point type available.
578   stdc is used in tests like "if (stdc)", which is less ugly than #ifdef.
579   U is output after unsigned constants.
580 */
581#ifdef STDC
582
583#define ARGS(x) x
584#define NOARGS (void)
585#define Volatile volatile
586#define Long_double long double
587#define stdc 1
588#define U "U"
589
590#else /* Old style C */
591
592#define ARGS(x) ()
593#define NOARGS ()
594#define Volatile static
595#define Long_double double
596#define stdc 0
597#define U ""
598
599#endif /* STDC */
600
601/* include files */
602#include <stdio.h>
603#include  <wchar.h>
604
605#ifdef STDC
606#ifndef BAD_STDDEF
607#include <stddef.h> /* for size_t: if this fails, define BAD_STDDEF */
608#endif
609#endif
610
611#ifdef NO_SIG
612#define jmp_buf int
613#else
614#include <signal.h> /* if this fails, define NO_SIG */
615#include <setjmp.h> /* if this fails, define NO_SIG */
616#endif
617//#ifndef NO_SIG
618//#include <signal.h> /* if this fails, define NO_SIG */
619//#include <setjmp.h> /* if this fails, define NO_SIG */
620//#endif
621
622/* Kludge around the possiblity that <stdio.h> includes <limits.h> */
623#ifdef CHAR_BIT
624#undef CHAR_BIT
625#undef CHAR_MAX
626#undef CHAR_MIN
627#undef SCHAR_MAX
628#undef SCHAR_MIN
629#undef UCHAR_MAX
630#undef UCHAR_MIN
631#endif
632
633#ifdef VERIFY
634#include "limits.h"
635#include "float.h"
636#endif
637
638/* The largest unsigned type */
639#ifdef NO_UI
640#define ulong unsigned int
641#else
642#define ulong unsigned long
643#endif
644
645/* Some shorthands */
646#define Vprintf if (V) printf
647#define Unexpected(place) if (setjmp(lab)!=0) croak(place)
648#define fabs(x) (((x)<0.0)?(-x):(x))
649
650#endif /* PASS */
651
652/* A description of the ANSI constants */
653#define D_CHAR_BIT "Number of bits in a storage unit"
654#define D_CHAR_MAX "Maximum char"
655#define D_CHAR_MIN "Minimum char"
656#define D_SCHAR_MAX "Maximum signed char"
657#define D_SCHAR_MIN "Minimum signed char"
658#define D_UCHAR_MAX "Maximum unsigned char (minimum is always 0)"
659
660#define D_INT_MAX "Maximum %s"
661#define D_INT_MIN "Minimum %s"
662#define D_UINT_MAX "Maximum unsigned %s (minimum is always 0)"
663
664#define D_FLT_ROUNDS "Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown"
665#define D_FLT_RADIX "Radix of exponent representation"
666#define D_MANT_DIG "Number of base-FLT_RADIX digits in the significand of a %s"
667#define D_DIG "Number of decimal digits of precision in a %s"
668#define D_MIN_EXP "Minimum int x such that FLT_RADIX**(x-1) is a normalised %s"
669#define D_MIN_10_EXP "Minimum int x such that 10**x is a normalised %s"
670#define D_MAX_EXP "Maximum int x such that FLT_RADIX**(x-1) is a representable %s"
671#define D_MAX_10_EXP "Maximum int x such that 10**x is a representable %s"
672#define D_MAX "Maximum %s"
673#define D_EPSILON "Difference between 1.0 and the minimum %s greater than 1.0"
674#define D_MIN "Minimum normalised %s"
675
676#ifdef PASS0
677
678/* Prototypes for what's to come: */
679
680int false NOARGS;
681
682#ifdef BAD_STDDEF
683char *malloc (); /* Old style prototype, since we don't know what size_t is */
684#else
685char *malloc ARGS((size_t size));
686#endif
687Void free ARGS((char *p)); /* Syntax error here? Try -DNO_VOID */
688
689Void exit ARGS((int status));
690
691char *f_rep ARGS((int precision, Long_double val));
692
693int maximum_int NOARGS;
694int cprop NOARGS;
695int basic NOARGS;
696Void sprop NOARGS;
697Void iprop NOARGS;
698Void lprop NOARGS;
699Void usprop NOARGS;
700Void uiprop NOARGS;
701Void ulprop NOARGS;
702int fprop ARGS((int byte_size));
703int dprop ARGS((int byte_size));
704int ldprop ARGS((int byte_size));
705Void efprop ARGS((int fprec, int dprec, int lprec));
706Void edprop ARGS((int fprec, int dprec, int lprec));
707Void eldprop ARGS((int fprec, int dprec, int lprec));
708
709int setmode ARGS((char *s));
710Void farewell ARGS((int bugs));
711Void describe ARGS((char *description, char *extra));
712Void missing ARGS((char *s));
713Void fmissing ARGS((char *s));
714Void check_defines NOARGS;
715Void bitpattern ARGS((char *p, unsigned int size));
716int ceil_log ARGS((int base, Long_double x));
717Void croak ARGS((int place));
718Void trap1 ARGS((int sig));
719Void eek_a_bug ARGS((char *problem));
720Void endian ARGS((int byte_size));
721int exponent ARGS((Long_double x, Long_double *fract, int *exp));
722int floor_log ARGS((int base, Long_double x));
723Void f_define ARGS((char *desc, char *extra, char *sort, char *name,
724       int prec, Long_double val, char *mark));
725Void i_define ARGS((char *desc, char *extra, char *sort, char *name,
726       long val, long lim, long req, char *mark));
727Void u_define ARGS((char *desc, char *extra, char *sort, char *name,
728       ulong val, ulong req, char *mark));
729
730#ifdef NO_SIG  /* There's no signal(), or setjmp/longjmp() */
731
732  /* Dummy routines instead */
733  typedef int jmp_buf;
734
735  int setjmp ARGS((jmp_buf lab));
736
737  jmp_buf lab, mlab;
738  int setjmp(jmp_buf lab) { return(0); }
739  void  longjmp(jmp_buf lab, int val) { return; }
740
741  Void signal(int i, void (*p)()) {}
742
743#else
744  jmp_buf lab, mlab;
745  Void overflow(int sig)
746  { /* what to do on over/underflow */
747    signal(sig, overflow);
748    longjmp(lab, 1);
749  }
750
751  Void address(int sig)
752  { /* what to do on an address error */
753    signal(sig, address);
754    longjmp(mlab, 1);
755  }
756
757#endif /*NO_SIG*/
758
759int V= 0, /* verbose */
760    L= 0, /* produce limits.h */
761    F= 0, /* produce float.h  */
762    bugs=0; /* The number of (possible) bugs in the output */
763
764char co[4], oc[4]; /* Comment starter and ender symbols */
765
766int bits_per_byte; /* the number of bits per unit returned by sizeof() */
767int flt_rounds;    /* The calculated value of FLT_ROUNDS */
768int flt_radix;     /* The calculated value of FLT_RADIX */
769Volatile int trapped; /* For testing FPE traps */
770
771#ifdef TEST
772/* Set the fp modes on a SUN with 68881 chip, to check that different
773   rounding modes etc. get properly detected.
774   Compile with -f68881 for cc, -m68881 for gcc, and with additional flag
775   -DTEST. Run with additional parameter +hex-number, to set the 68881 mode
776   register to hex-number
777*/
778
779/* Bits 0x30 = rounding mode */
780#define ROUND_BITS  0x30
781#define TO_NEAREST  0x00
782#define TO_ZERO   0x10
783#define TO_MINUS_INF  0x20
784#define TO_PLUS_INF 0x30 /* The SUN FP user's guide seems to be wrong here */
785
786/* Bits 0xc0 = extended rounding */
787#define EXT_BITS  0xc0
788#define ROUND_EXTENDED  0x00
789#define ROUND_SINGLE  0x40
790#define ROUND_DOUBLE  0x80
791
792/* Enabled traps */
793#define EXE_INEX1  0x100
794#define EXE_INEX2  0x200
795#define EXE_DZ     0x400
796#define EXE_UNFL   0x800
797#define EXE_OVFL  0x1000
798#define EXE_OPERR 0x2000
799#define EXE_SNAN  0x4000
800#define EXE_BSUN  0x8000
801
802/* Only used for testing, on a Sun with 68881 chip */
803/* Print the FP mode */
804printmode(new) unsigned new; {
805  fpmode_(&new);
806  printf("New fp mode:\n");
807  printf("  Round toward ");
808  switch (new & ROUND_BITS) {
809        case TO_NEAREST:   printf("nearest"); break;
810        case TO_ZERO:      printf("zero"); break;
811        case TO_MINUS_INF: printf("minus infinity"); break;
812        case TO_PLUS_INF:  printf("plus infinity"); break;
813        default: printf("???"); break;
814  }
815
816  printf("\n  Extended rounding precision: ");
817
818  switch (new & EXT_BITS) {
819        case ROUND_EXTENDED: printf("extended"); break;
820        case ROUND_SINGLE:   printf("single"); break;
821        case ROUND_DOUBLE:   printf("double"); break;
822        default: printf("???"); break;
823  }
824
825  printf("\n  Enabled exceptions:");
826  if (new & (unsigned) EXE_INEX1) printf(" inex1");
827  if (new & (unsigned) EXE_INEX2) printf(" inex2");
828  if (new & (unsigned) EXE_DZ)    printf(" divz");
829  if (new & (unsigned) EXE_UNFL)  printf(" unfl");
830  if (new & (unsigned) EXE_OVFL)  printf(" ovfl");
831  if (new & (unsigned) EXE_OPERR) printf(" operr");
832  if (new & (unsigned) EXE_SNAN)  printf(" snan");
833  if (new & (unsigned) EXE_BSUN)  printf(" bsun");
834  printf("\n");
835}
836
837/* Only used for testing, on a Sun with 68881 chip */
838/* Set the FP mode */
839int setmode(s) char *s; {
840  unsigned mode=0, dig;
841  char c;
842
843  while (*s) {
844    c= *s++;
845    if  (c>='0' && c<='9') dig= c-'0';
846    else if (c>='a' && c<='f') dig= c-'a'+10;
847    else if (c>='A' && c<='F') dig= c-'A'+10;
848    else return 1;
849    mode= mode<<4 | dig;
850  }
851  printmode(mode);
852  return 0;
853}
854#define SETMODE
855#endif
856
857#ifdef TESTI /* Test mode using SunOs IEEE routines */
858
859#include <sys/ieeefp.h>
860
861int setmode(char *s) {
862  char *dummy, c, *cmd, *val;
863  while (*s) {
864    switch (c= *s++) {
865          case '=': cmd= "direction"; val= "nearest"; break;
866          case '0': cmd= "direction"; val= "tozero"; break;
867          case '+': cmd= "direction"; val= "positive"; break;
868          case '-': cmd= "direction"; val= "negative"; break;
869          case '1': cmd= "precision"; val= "single"; break;
870          case '2': cmd= "precision"; val= "double"; break;
871          case '3': cmd= "precision"; val= "extended"; break;
872          case '~': cmd= "exception"; val= "inexact"; break;
873          case '/': cmd= "exception"; val= "division"; break;
874          case '>': cmd= "exception"; val= "overflow"; break;
875          case '<': cmd= "exception"; val= "underflow"; break;
876          default:
877      printf("Bad setmode character: %c\n", c);
878      return 1;
879      break;
880    }
881    printf("Set %s %s", cmd, val);
882    if (ieee_flags("set", cmd, val, &dummy)) {
883      printf(": failed\n");
884      return 1;
885    }
886    printf("\n");
887  }
888  return 0;
889}
890#define SETMODE
891#endif
892
893#ifndef SETMODE
894/* ARGSUSED */
895int
896setmode(char *s)
897{
898  fprintf(stderr, "Can't set mode: not compiled with TEST\n");
899  return(1);
900}
901#endif
902
903int
904memeq(
905  char *p1,
906  int size1,
907  char *p2,
908  int size2
909  )
910{
911  /* See if two blocks of store are identical */
912  int i;
913  if (size1 != size2) return 0;
914  for (i=1; i<=size1; i++) {
915    if (*p1++ != *p2++) return 0;
916  }
917  return 1;
918}
919
920Void
921farewell(int bugs)
922{
923  if (bugs == 0) exit(0);
924  printf("\n%sFor hints on dealing with the ", co);
925  if (bugs == 1) printf("problem");
926  else printf("%d problems", bugs);
927  printf(" above\n   see the section 'TROUBLESHOOTING' in the file ");
928  printf("%s%s\n", FILENAME, oc);
929  exit(bugs);
930}
931
932/* The program has received a signal where it wasn't expecting one */
933Void
934croak(int place)
935{
936  printf("*** Unexpected signal at point %d\n", place);
937  farewell(bugs+1); /* An exit isn't essential here, but avoids loops */
938}
939
940/* This is here in case alloca.c is used, which calls this. */
941char *
942xmalloc(unsigned size)
943{
944  char *value = malloc(size);
945  if (value == 0) {
946    fprintf(stderr, "Virtual memory exceeded\n");
947    exit(bugs+1);
948  }
949  return value;
950}
951
952int maxint;
953
954int
955maximum_int( void )
956{
957  /* Find the maximum integer */
958  Volatile int newi, int_max, two=2;
959
960  /* Calculate maxint ***********************************/
961  /* Calculate 2**n-1 until overflow - then use the previous value  */
962
963  newi=1; int_max=0;
964
965  if (setjmp(lab)==0) { /* Yields int_max */
966    while(newi>int_max) {
967      int_max=newi;
968      newi=newi*two+1;
969    }
970  }
971  Unexpected(0);
972  return int_max;
973}
974
975/* How long are my identifiers? I could go further here, but some compilers
976   have line length limits that I don't want to break.
977*/
978
979int zzzzzzzzz1zzzzzzzzz2zzzzzzzzz3zzzzzzzzz4zzzzzzzzz5zzzzzzzzz6zzzz=64;
980
981int
982name_len( void )
983{
984   int zzzzzzzzz1zzzzzzzzz2zzzzzzzzz3zz=32;
985   { int zzzzzzzzz1zzzzzz=16;
986     { int zzzzzzzz=8;
987       { int zzzzzzz=7;
988   { int zzzzzz=6;
989     return
990       zzzzzzzzz1zzzzzzzzz2zzzzzzzzz3zzzzzzzzz4zzzzzzzzz5zzzzzzzzz6zzzz;
991   }
992       }
993     }
994   }
995}
996
997#define aaaaaaaaa1aaaaaaaaa2aaaaaaaaa3aaaaaaaaa4aaaaaaaaa5aaaaaaaaa6aaaa 64
998#define LENGTH 64
999
1000#ifdef aaaaaaaaa1aaaaaaaaa2aaaaaaaaa3aa
1001#undef LENGTH
1002#define LENGTH 32
1003#endif
1004
1005#ifdef aaaaaaaaa1aaaaaa
1006#undef LENGTH
1007#define LENGTH 16
1008#endif
1009
1010#ifdef aaaaaaaa
1011#undef LENGTH
1012#define LENGTH 8
1013#endif
1014
1015#undef aaaaaaaaa1aaaaaaaaa2aaaaaaaaa3aaaaaaaaa4aaaaaaaaa5aaaaaaaaa6aaaa
1016
1017Void long_names()
1018{
1019  int l= name_len();
1020  Vprintf("Compiler names are at least %d chars long", l);
1021  if (l != 64)
1022    Vprintf(" (but less than %d)", l*2);
1023  Vprintf("\n");
1024  Vprintf("Preprocessor names are at least %d long", LENGTH);
1025  if (LENGTH != 64)
1026    Vprintf(" (but less than %d)", LENGTH*2);
1027  Vprintf("\n\n");
1028}
1029
1030/* Used by FPROP to see if FP traps are generated, and if they may return */
1031
1032Void
1033trap2(int sig)
1034{
1035  longjmp(lab, 1);
1036}
1037
1038Void
1039trap1(int sig)
1040{
1041  trapped= 1; /* A global */
1042  signal(sig, trap2);
1043}
1044
1045Void
1046setsignals( void )
1047{
1048#ifdef SIGFPE
1049  signal(SIGFPE, overflow);
1050#endif
1051#ifdef SIGOVER
1052  signal(SIGOVER, overflow);
1053#endif
1054#ifdef SIGBUS
1055  signal(SIGBUS, address);
1056#endif
1057#ifdef SIGSEGV
1058  signal(SIGSEGV, address);
1059#endif
1060  /* Add more calls as necessary */
1061}
1062
1063#undef LENGTH
1064
1065int
1066main(int argc, char *argv[])
1067{
1068  int dprec, fprec, lprec;
1069  int i;
1070  wchar_t *s;
1071  int bad;
1072
1073  setsignals();
1074  Unexpected(1);
1075
1076  bad=0;
1077  for (i=1; i < argc; i++) {
1078    s = (wchar_t *)(argv[i]);
1079    if (*s == L'-') {
1080      s++;
1081      while (*s) {
1082        switch (*(s++)) {
1083              case L'v': V=1; break;
1084              case L'l': L=1; break;
1085              case L'f': F=1; break;
1086              default: bad=1; break;
1087        }
1088      }
1089    } else if (*s == L'+') {
1090      s++;
1091      bad = setmode((char *)s);
1092    } else bad= 1;
1093  }
1094  if (bad) {
1095    fprintf(stderr,
1096      "Usage: %ls [-vlf]\n  v=Verbose l=Limits.h f=Float.h\n",
1097      (wchar_t *)(argv[0]));
1098    exit(1);
1099  }
1100  if (L || F) {
1101    co[0]= '/'; oc[0]= ' ';
1102    co[1]= '*'; oc[1]= '*';
1103    co[2]= ' '; oc[2]= '/';
1104    co[3]= '\0'; oc[3]= '\0';
1105  } else {
1106    co[0]= '\0'; oc[0]= '\0';
1107    V=1;
1108  }
1109
1110  if (L) printf("%slimits.h%s\n", co, oc);
1111  if (F) printf("%sfloat.h%s\n", co, oc);
1112#ifdef ID
1113  printf("%sProduced by enquire version %s (%s), CWI, Amsterdam\n   %s\n",
1114         co, VERSION, ID, WEB, oc);
1115#else
1116  printf("%sProduced by enquire version %s, CWI, Amsterdam\n   %s %s\n",
1117         co, VERSION,     WEB, oc);
1118#endif
1119
1120#ifdef VERIFY
1121  printf("%sVerification phase%s\n", co, oc);
1122#endif
1123
1124#ifdef NO_SIG
1125  Vprintf("%sCompiled without signal(): %s%s\n",
1126    co,
1127    "there's nothing that can be done if overflow occurs",
1128    oc);
1129#endif
1130#ifdef NO_SC
1131  Vprintf("%sCompiled without signed char%s\n", co, oc);
1132#endif
1133#ifdef NO_UC
1134  Vprintf("%sCompiled without unsigned char%s\n", co, oc);
1135#endif
1136#ifdef NO_UI
1137  Vprintf("%sCompiled without unsigned short or long%s\n", co, oc);
1138#endif
1139#ifdef __STDC__
1140  Vprintf("%sCompiler claims to be ANSI C level %d%s\n",
1141    co, __STDC__, oc);
1142#else
1143  Vprintf("%sCompiler does not claim to be ANSI C%s\n", co, oc);
1144#endif
1145  printf("\n");
1146
1147  long_names();
1148  check_defines();
1149
1150  maxint= maximum_int();
1151  bits_per_byte= basic();
1152  Vprintf("\n");
1153  if (F||V) {
1154    fprec= fprop(bits_per_byte);
1155    dprec= dprop(bits_per_byte);
1156    lprec= ldprop(bits_per_byte);
1157    efprop(fprec, dprec, lprec);
1158    edprop(fprec, dprec, lprec);
1159    eldprop(fprec, dprec, lprec);
1160  }
1161#ifndef BAD_MALLOC
1162  if (V) {
1163    /* An extra goody: the approximate amount of data-space */
1164    /* Allocate store until no more available */
1165    /* Different implementations have a different argument type
1166       to malloc. Here we assume that it's the same type as
1167       that which sizeof() returns */
1168    unsigned int size;
1169    Volatile long total;
1170    char kmg, *ptr, *save;
1171    char **link;
1172
1173    save= NULL;
1174    size=maximum_int()/4;
1175    total=0;
1176    while (size!=0) {
1177      if (setjmp(mlab) == 0) {
1178        while ((ptr= malloc((false()?sizeof(int):size))) != (char *)NULL) {
1179          //if (save == NULL) save= ptr; /* save the biggest chunk */
1180          link = (char **)ptr;
1181          if (save == NULL) {
1182            // Save pointer to first allocated chunk
1183            save= ptr;
1184            *link = NULL;
1185          }
1186          else {
1187            // Build list of all subsequently allocated chunks, LIFO
1188            *link = save;
1189            save = ptr;
1190          }
1191          total+=(size/2);
1192        }
1193      } else {
1194        eek_a_bug("Trying to malloc all store generates a trap");
1195      }
1196      size/=2;
1197    }
1198    if (setjmp(mlab)!=0) croak(-1);
1199
1200    //if (save != NULL) free(save);
1201    while(save != NULL) {
1202      link = (char **)save;
1203      ptr = *link;
1204      free(save);
1205      save = ptr;
1206    }
1207
1208    total= (total+511)/512; /* Sic */ kmg= 'K';
1209    if (total > 10000) {
1210      total= (total+999)/1000; kmg= 'M';
1211    }
1212    if (total > 10000) {
1213      total= (total+999)/1000; kmg= 'G';
1214    }
1215    if (total > 10000) {
1216      total= (total+999)/1000; kmg= 'T';
1217    }
1218    Vprintf("%sMemory mallocatable ~= %ld %cbytes%s\n",
1219      co, total, kmg, oc);
1220  }
1221#endif
1222  farewell(bugs);
1223  return bugs; /* To keep compilers and lint happy */
1224}
1225
1226Void
1227eek_a_bug(char *problem)
1228{
1229  /* The program has discovered a problem */
1230  printf("\n%s*** WARNING: %s%s\n", co, problem, oc);
1231  bugs++;
1232}
1233
1234Void
1235describe(char *description, char *extra)
1236{
1237  /* Produce the description for a #define */
1238  printf("   %s", co);
1239  printf(description, extra);
1240  printf("%s\n", oc);
1241}
1242
1243Void
1244i_define(
1245   char *desc,
1246   char *extra,
1247   char *sort,
1248   char *name,
1249   long val,
1250   long lim,
1251   long req,
1252   char *mark
1253  )
1254{
1255  /* Produce a #define for a signed int type */
1256  describe(desc, extra);
1257  if (val >= 0) {
1258    printf("#define %s%s %ld%s\n", sort, name, val, mark);
1259  } else if (val + lim < 0) {
1260    /* We may not produce a constant like -1024 if the max
1261       allowable value is 1023. It has then to be output as
1262       -1023-1. lim is the max allowable value. */
1263    printf("#define %s%s (%ld%s%ld%s)\n",
1264           sort, name, -lim, mark, val+lim, mark);
1265  } else {
1266    printf("#define %s%s (%ld%s)\n", sort, name, val, mark);
1267  }
1268  /* If VERIFY is not set, val and req are just the same value;
1269     if it is set, val is the value as calculated, and req is
1270     the #defined constant
1271  */
1272  if (val != req) {
1273    printf("%s*** Verify failed for above #define!\n", co);
1274    printf("       Compiler has %ld for value%s\n\n", req, oc);
1275    bugs++;
1276  }
1277  Vprintf("\n");
1278}
1279
1280Void
1281u_define(
1282  char *desc,
1283  char *extra,
1284  char *sort,
1285  char *name,
1286  ulong val,
1287  ulong req,
1288  char *mark
1289  )
1290{
1291  /* Produce a #define for an unsigned value */
1292  describe(desc, extra);
1293  printf("#define %s%s %lu%s%s\n", sort, name, val, U, mark);
1294  if (val != req) {
1295    printf("%s*** Verify failed for above #define!\n", co);
1296    printf("       Compiler has %lu for value%s\n\n", req, oc);
1297    bugs++;
1298  }
1299  Vprintf("\n");
1300}
1301
1302Void f_define(
1303  char *desc,
1304  char *extra,
1305  char *sort,
1306  char *name,
1307  int precision,
1308  Long_double val,
1309  char *mark
1310  )
1311{
1312  /* Produce a #define for a float/double/long double */
1313  describe(desc, extra);
1314  if (stdc) {
1315    printf("#define %s%s %s%s\n",
1316           sort, name, f_rep(precision, val), mark);
1317  } else if (*mark == 'F') {
1318    /* non-ANSI C has no float constants, so cast the constant */
1319    printf("#define %s%s ((float)%s)\n",
1320           sort, name, f_rep(precision, val));
1321  } else {
1322    printf("#define %s%s %s\n", sort, name, f_rep(precision, val));
1323  }
1324  Vprintf("\n");
1325}
1326
1327int
1328floor_log(int base, Long_double x)
1329{
1330  /* return floor(log base(x)) */
1331  int r=0;
1332  while (x>=base) { r++; x/=base; }
1333  return r;
1334}
1335
1336int
1337ceil_log(int base, Long_double x)
1338{
1339  int r=0;
1340  while (x>1.0) { r++; x/=base; }
1341  return r;
1342}
1343
1344int
1345exponent(Long_double x, Long_double *fract, int *exp)
1346{
1347  /* Split x into a fraction and a power of ten;
1348     returns 0 if x is unusable, 1 otherwise.
1349     Only used for error messages about faulty output.
1350  */
1351  int r=0, neg=0;
1352  Long_double old;
1353  *fract=0.0; *exp=0;
1354  if (x<0.0) {
1355    x= -x;
1356    neg= 1;
1357  }
1358  if (x==0.0) return 1;
1359  if (x>=10.0) {
1360    while (x>=10.0) {
1361      old=x; r++; x/=10.0;
1362      if (old==x) return 0;
1363    }
1364  } else {
1365    while (x<1.0) {
1366      old=x; r--; x*=10.0;
1367      if (old==x) return 0;
1368    }
1369  }
1370  if (neg) *fract= -x;
1371  else *fract= x;
1372  *exp=r;
1373  return 1;
1374}
1375
1376char *
1377f_rep(int precision, Long_double val)
1378{
1379  /* Return the floating representation of val */
1380  static char buf[1024];
1381  char *f1;
1382  if (sizeof(double) == sizeof(Long_double)) {
1383    /* Assume they're the same, and use non-stdc format */
1384    /* This is for stdc compilers using non-stdc libraries */
1385    f1= "%.*e";
1386  } else {
1387    /* It had better support Le then */
1388    f1= "%.*Le";
1389  }
1390  sprintf(buf, f1, precision, val);
1391  return buf;
1392}
1393
1394Void
1395bitpattern(char *p, unsigned int size)
1396{
1397  /* Printf the bit-pattern of p */
1398  char c;
1399  unsigned int i;
1400  int j;
1401
1402  for (i=1; i<=size; i++) {
1403    c= *p;
1404    p++;
1405    for (j=bits_per_byte-1; j>=0; j--)
1406      printf("%c", (c>>j)&1 ? '1' : '0');
1407    if (i!=size) printf(" ");
1408  }
1409}
1410
1411Void
1412fill(char *p, int size)
1413{
1414  char *ab= "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1415  int i;
1416
1417  for (i=0; i<size; i++)
1418    p[i]= ab[i];
1419}
1420
1421#define Order(x, mode)\
1422   printf("%s%s ", co, mode); fill((char *)&x, sizeof(x)); \
1423   for (i=1; i<=sizeof(x); i++) { c=((x>>(byte_size*(sizeof(x)-i)))&mask);\
1424      putchar(c==0 ? '?' : (char)c); }\
1425   printf("%s\n", oc);
1426
1427Void
1428endian(int byte_size)
1429{
1430  /* Printf the byte-order used on this machine */
1431  /*unsigned*/ short s=0;
1432  /*unsigned*/ int j=0;
1433  /*unsigned*/ long l=0;
1434
1435  unsigned int mask, i, c;
1436
1437  mask=0;
1438  for (i=1; i<=(unsigned)byte_size; i++) mask= (mask<<1)|1;
1439
1440  if (V) {
1441    printf("%sCHARACTER ORDER%s\n", co, oc);
1442    Order(s, "short:");
1443    Order(j, "int:  ");
1444    Order(l, "long: ");
1445  }
1446}
1447
1448Void
1449missing(char *s)
1450{
1451  printf("%s*** #define %s missing from limits.h%s\n", co, s, oc);
1452  bugs++;
1453}
1454
1455Void
1456fmissing(char *s)
1457{
1458  printf("%s*** #define %s missing from float.h%s\n", co, s, oc);
1459  bugs++;
1460}
1461
1462/* To try and fool optimisers */
1463int false( void ) { return 0; }
1464
1465#define Promoted(x) (false()?(x):(-1))
1466#define is_signed(x) (Promoted(x) < 0)
1467#define sign_of(x) (is_signed(x)?"signed":"unsigned")
1468#define Signed 1
1469#define Unsigned 0
1470#define sgn(x) ((is_signed(x))?Signed:Unsigned)
1471
1472#define showtype(t, x) Vprintf("%s%s %s %s%s\n", co, t, sign_of(x), type_of((int)sizeof(x)), oc)
1473
1474char *type_of(int x)
1475{
1476  if (x == sizeof(char)) {
1477    if (sizeof(char) == sizeof(int)) return "char/short/int";
1478    if (sizeof(char) == sizeof(short)) return "char/short";
1479    return "char";
1480  }
1481  if (x == sizeof(short)) {
1482    if (sizeof(short) == sizeof(int)) return "short/int";
1483    return "short";
1484  }
1485  if (x == sizeof(int)) {
1486    if (sizeof(int) == sizeof(long)) return "int/long";
1487    return "int";
1488  }
1489  if (x == sizeof(long)) return "long";
1490  return "unknown-type";
1491}
1492
1493char *ftype_of(int x)
1494{
1495  if (x == sizeof(float)) {
1496    return "float";
1497  }
1498  if (x == sizeof(double)) {
1499    if (sizeof(double) == sizeof(Long_double))
1500      return "(long)double";
1501    return "double";
1502  }
1503  if (x == sizeof(Long_double)) {
1504    return "long double";
1505  }
1506  return "unknown-type";
1507}
1508
1509Void typerr(char *name, int esign, int esize, int sign, int size)
1510{
1511  Vprintf("*** %s has wrong type: expected %s %s, found %s %s\n",
1512    name, sign_of(esign), type_of(esize),
1513    sign_of(sign), type_of(size));
1514}
1515
1516Void ftyperr(char *name, int esize, int size)
1517{
1518  Vprintf("*** %s has wrong type: expected %s, found %s\n",
1519    name, ftype_of(esize), ftype_of(size));
1520}
1521
1522Void promotions( void )
1523{
1524  int si; long sl;
1525  unsigned int ui;
1526  short ss;
1527
1528#ifndef NO_UI
1529  unsigned long ul;  /* if this fails, define NO_UI */
1530  unsigned short us; /* if this fails, define NO_UI */
1531
1532  ul=0; us=0;
1533#endif
1534  /* Shut compiler warnings up: */
1535  si=0; sl=0; ui=0; ss=0;
1536
1537  Vprintf("\n%sPROMOTIONS%s\n", co, oc);
1538
1539  /* Sanity checks. Possible warnings here; should be no problem */
1540  if (is_signed(ui))
1541    eek_a_bug("unsigned int promotes to signed!\n");
1542  if (!is_signed(si))
1543    eek_a_bug("signed int promotes to unsigned!\n");
1544  if (!is_signed(sl))
1545    eek_a_bug("signed long promotes to unsigned!\n");
1546  if (sizeof(Promoted(si)) != sizeof(int))
1547    eek_a_bug("int doesn't promote to int!\n");
1548  if (sizeof(Promoted(sl)) != sizeof(long))
1549    eek_a_bug("long doesn't promote to long!\n");
1550  if (sizeof(Promoted(ss)) != sizeof(int))
1551    eek_a_bug("short doesn't promote to int!\n");
1552  if (sizeof(Promoted(ui)) != sizeof(int))
1553    eek_a_bug("unsigned int doesn't promote to int!\n");
1554#ifndef NO_UI
1555  if (sizeof(Promoted(ul)) != sizeof(long))
1556    eek_a_bug("unsigned long doesn't promote to long!\n");
1557  if (is_signed(ul))
1558    eek_a_bug("unsigned long promotes to signed!\n");
1559#endif
1560
1561#ifndef NO_UI
1562  showtype("unsigned short promotes to", Promoted(us));
1563#endif
1564  showtype("long+unsigned gives", sl+ui);
1565}
1566
1567#define checktype(x, n, s, t) if((sgn(x)!=s)||(sizeof(x)!=sizeof(t))) typerr(n, s, (int)sizeof(t), sgn(x), (int)sizeof(x));
1568
1569#define fchecktype(x, n, t) if (sizeof(x) != sizeof(t)) ftyperr(n, (int)sizeof(x), (int)sizeof(t));
1570
1571Void check_defines( void )
1572{
1573  /* ensure that all #defines are present and have the correct type */
1574#ifdef VERIFY
1575  int usign;
1576
1577#ifdef NO_UI
1578  usign= Signed;
1579#else
1580  /* Implementations promote unsigned short differently */
1581  usign= is_signed((unsigned short)0);
1582#endif
1583
1584  if (L) {
1585#ifdef CHAR_BIT
1586  checktype(CHAR_BIT, "CHAR_BIT", Signed, int);
1587#else
1588  missing("CHAR_BIT");
1589#endif
1590#ifdef CHAR_MAX
1591  checktype(CHAR_MAX, "CHAR_MAX", Signed, int);
1592#else
1593  missing("CHAR_MAX");
1594#endif
1595#ifdef CHAR_MIN
1596  checktype(CHAR_MIN, "CHAR_MIN", Signed, int);
1597#else
1598  missing("CHAR_MIN");
1599#endif
1600#ifdef SCHAR_MAX
1601  checktype(SCHAR_MAX, "SCHAR_MAX", Signed, int);
1602#else
1603  missing("SCHAR_MAX");
1604#endif
1605#ifdef SCHAR_MIN
1606  checktype(SCHAR_MIN, "SCHAR_MIN", Signed, int);
1607#else
1608  missing("SCHAR_MIN");
1609#endif
1610#ifdef UCHAR_MAX
1611  checktype(UCHAR_MAX, "UCHAR_MAX", Signed, int);
1612#else
1613  missing("UCHAR_MAX");
1614#endif
1615#ifdef SHRT_MAX
1616  checktype(SHRT_MAX, "SHRT_MAX", Signed, int);
1617#else
1618  missing("SHRT_MAX");
1619#endif
1620#ifdef SHRT_MIN
1621  checktype(SHRT_MIN, "SHRT_MIN", Signed, int);
1622#else
1623  missing("SHRT_MIN");
1624#endif
1625#ifdef INT_MAX
1626  checktype(INT_MAX, "INT_MAX", Signed, int);
1627#else
1628  missing("INT_MAX");
1629#endif
1630#ifdef INT_MIN
1631  checktype(INT_MIN, "INT_MIN", Signed, int);
1632#else
1633  missing("INT_MIN");
1634#endif
1635#ifdef LONG_MAX
1636  checktype(LONG_MAX, "LONG_MAX", Signed, long);
1637#else
1638  missing("LONG_MAX");
1639#endif
1640#ifdef LONG_MIN
1641  checktype(LONG_MIN, "LONG_MIN", Signed, long);
1642#else
1643  missing("LONG_MIN");
1644#endif
1645#ifdef USHRT_MAX
1646  checktype(USHRT_MAX, "USHRT_MAX", usign, int);
1647#else
1648  missing("USHRT_MAX");
1649#endif
1650#ifdef UINT_MAX
1651  checktype(UINT_MAX, "UINT_MAX", Unsigned, int);
1652#else
1653  missing("UINT_MAX");
1654#endif
1655#ifdef ULONG_MAX
1656  checktype(ULONG_MAX, "ULONG_MAX", Unsigned, long);
1657#else
1658  missing("ULONG_MAX");
1659#endif
1660  } /* if (L) */
1661
1662  if (F) {
1663#ifdef FLT_RADIX
1664  checktype(FLT_RADIX, "FLT_RADIX", Signed, int);
1665#else
1666  fmissing("FLT_RADIX");
1667#endif
1668#ifdef FLT_MANT_DIG
1669  checktype(FLT_MANT_DIG, "FLT_MANT_DIG", Signed, int);
1670#else
1671  fmissing("FLT_MANT_DIG");
1672#endif
1673#ifdef FLT_DIG
1674  checktype(FLT_DIG, "FLT_DIG", Signed, int);
1675#else
1676  fmissing("FLT_DIG");
1677#endif
1678#ifdef FLT_ROUNDS
1679  checktype(FLT_ROUNDS, "FLT_ROUNDS", Signed, int);
1680#else
1681  fmissing("FLT_ROUNDS");
1682#endif
1683#ifdef FLT_EPSILON
1684  fchecktype(FLT_EPSILON, "FLT_EPSILON", float);
1685#else
1686  fmissing("FLT_EPSILON");
1687#endif
1688#ifdef FLT_MIN_EXP
1689  checktype(FLT_MIN_EXP, "FLT_MIN_EXP", Signed, int);
1690#else
1691  fmissing("FLT_MIN_EXP");
1692#endif
1693#ifdef FLT_MIN
1694  fchecktype(FLT_MIN, "FLT_MIN", float);
1695#else
1696  fmissing("FLT_MIN");
1697#endif
1698#ifdef FLT_MIN_10_EXP
1699  checktype(FLT_MIN_10_EXP, "FLT_MIN_10_EXP", Signed, int);
1700#else
1701  fmissing("FLT_MIN_10_EXP");
1702#endif
1703#ifdef FLT_MAX_EXP
1704  checktype(FLT_MAX_EXP, "FLT_MAX_EXP", Signed, int);
1705#else
1706  fmissing("FLT_MAX_EXP");
1707#endif
1708#ifdef FLT_MAX
1709  fchecktype(FLT_MAX, "FLT_MAX", float);
1710#else
1711  fmissing("FLT_MAX");
1712#endif
1713#ifdef FLT_MAX_10_EXP
1714  checktype(FLT_MAX_10_EXP, "FLT_MAX_10_EXP", Signed, int);
1715#else
1716  fmissing("FLT_MAX_10_EXP");
1717#endif
1718#ifdef DBL_MANT_DIG
1719  checktype(DBL_MANT_DIG, "DBL_MANT_DIG", Signed, int);
1720#else
1721  fmissing("DBL_MANT_DIG");
1722#endif
1723#ifdef DBL_DIG
1724  checktype(DBL_DIG, "DBL_DIG", Signed, int);
1725#else
1726  fmissing("DBL_DIG");
1727#endif
1728#ifdef DBL_EPSILON
1729  fchecktype(DBL_EPSILON, "DBL_EPSILON", double);
1730#else
1731  fmissing("DBL_EPSILON");
1732#endif
1733#ifdef DBL_MIN_EXP
1734  checktype(DBL_MIN_EXP, "DBL_MIN_EXP", Signed, int);
1735#else
1736  fmissing("DBL_MIN_EXP");
1737#endif
1738#ifdef DBL_MIN
1739  fchecktype(DBL_MIN, "DBL_MIN", double);
1740#else
1741  fmissing("DBL_MIN");
1742#endif
1743#ifdef DBL_MIN_10_EXP
1744  checktype(DBL_MIN_10_EXP, "DBL_MIN_10_EXP", Signed, int);
1745#else
1746  fmissing("DBL_MIN_10_EXP");
1747#endif
1748#ifdef DBL_MAX_EXP
1749  checktype(DBL_MAX_EXP, "DBL_MAX_EXP", Signed, int);
1750#else
1751  fmissing("DBL_MAX_EXP");
1752#endif
1753#ifdef DBL_MAX
1754  fchecktype(DBL_MAX, "DBL_MAX", double);
1755#else
1756  fmissing("DBL_MAX");
1757#endif
1758#ifdef DBL_MAX_10_EXP
1759  checktype(DBL_MAX_10_EXP, "DBL_MAX_10_EXP", Signed, int);
1760#else
1761  fmissing("DBL_MAX_10_EXP");
1762#endif
1763#ifdef STDC
1764#ifdef LDBL_MANT_DIG
1765  checktype(LDBL_MANT_DIG, "LDBL_MANT_DIG", Signed, int);
1766#else
1767  fmissing("LDBL_MANT_DIG");
1768#endif
1769#ifdef LDBL_DIG
1770  checktype(LDBL_DIG, "LDBL_DIG", Signed, int);
1771#else
1772  fmissing("LDBL_DIG");
1773#endif
1774#ifdef LDBL_EPSILON
1775  fchecktype(LDBL_EPSILON, "LDBL_EPSILON", long double);
1776#else
1777  fmissing("LDBL_EPSILON");
1778#endif
1779#ifdef LDBL_MIN_EXP
1780  checktype(LDBL_MIN_EXP, "LDBL_MIN_EXP", Signed, int);
1781#else
1782  fmissing("LDBL_MIN_EXP");
1783#endif
1784#ifdef LDBL_MIN
1785  fchecktype(LDBL_MIN, "LDBL_MIN", long double);
1786#else
1787  fmissing("LDBL_MIN");
1788#endif
1789#ifdef LDBL_MIN_10_EXP
1790  checktype(LDBL_MIN_10_EXP, "LDBL_MIN_10_EXP", Signed, int);
1791#else
1792  fmissing("LDBL_MIN_10_EXP");
1793#endif
1794#ifdef LDBL_MAX_EXP
1795  checktype(LDBL_MAX_EXP, "LDBL_MAX_EXP", Signed, int);
1796#else
1797  fmissing("LDBL_MAX_EXP");
1798#endif
1799#ifdef LDBL_MAX
1800  fchecktype(LDBL_MAX, "LDBL_MAX", long double);
1801#else
1802  fmissing("LDBL_MAX");
1803#endif
1804#ifdef LDBL_MAX_10_EXP
1805  checktype(LDBL_MAX_10_EXP, "LDBL_MAX_10_EXP", Signed, int);
1806#else
1807  fmissing("LDBL_MAX_10_EXP");
1808#endif
1809#endif /* STDC */
1810  } /* if (F) */
1811#endif /* VERIFY */
1812}
1813
1814#ifdef VERIFY
1815#ifndef SCHAR_MAX
1816#define SCHAR_MAX char_max
1817#endif
1818#ifndef SCHAR_MIN
1819#define SCHAR_MIN char_min
1820#endif
1821#ifndef UCHAR_MAX
1822#define UCHAR_MAX char_max
1823#endif
1824#endif /* VERIFY */
1825
1826#ifndef CHAR_BIT
1827#define CHAR_BIT  char_bit
1828#endif
1829#ifndef CHAR_MAX
1830#define CHAR_MAX  char_max
1831#endif
1832#ifndef CHAR_MIN
1833#define CHAR_MIN  char_min
1834#endif
1835#ifndef SCHAR_MAX
1836#define SCHAR_MAX char_max
1837#endif
1838#ifndef SCHAR_MIN
1839#define SCHAR_MIN char_min
1840#endif
1841#ifndef UCHAR_MAX
1842#define UCHAR_MAX char_max
1843#endif
1844
1845int cprop( void )
1846{
1847  /* Properties of type char */
1848  Volatile char c, char_max, char_min;
1849  Volatile int byte_size, c_signed;
1850  long char_bit;
1851
1852  Unexpected(2);
1853
1854  /* Calculate number of bits per character *************************/
1855  c=1; byte_size=0;
1856  do { c=c<<1; byte_size++; } while(c!=0);
1857  c= (char)(-1);
1858  if (((int)c)<0) c_signed=1;
1859  else c_signed=0;
1860  Vprintf("%schar = %d bits, %ssigned%s\n",
1861    co, (int)sizeof(c)*byte_size, (c_signed?"":"un"), oc);
1862  char_bit=(long)(sizeof(c)*byte_size);
1863  if (L) i_define(D_CHAR_BIT, "", "CHAR", "_BIT",
1864      char_bit, 0L, (long) CHAR_BIT, "");
1865
1866  c=0; char_max=0;
1867  c++;
1868  if (setjmp(lab)==0) { /* Yields char_max */
1869    while (c>char_max) {
1870      char_max=c;
1871      c=(char)(c*2+1);
1872    }
1873  } else {
1874    Vprintf("%sCharacter overflow generates a trap!%s\n", co, oc);
1875  }
1876  c=0; char_min=0;
1877  c--;
1878  if (c<char_min) /* then the min char < 0 */ {
1879     /* Minimum value: assume either two's or one's complement *********/
1880    char_min= -char_max;
1881    if (setjmp(lab)==0) { /* Yields char_min */
1882        if (char_min-1 < char_min) char_min--;
1883    }
1884  }
1885  Unexpected(8);
1886  if (c_signed && char_min == 0) {
1887    Vprintf("%sBEWARE! Chars are pseudo-unsigned:%s\n", co, oc);
1888    Vprintf("%s   %s%s%s\n",
1889      "They contain only nonnegative values, ",
1890      "but sign extend when used as integers.", co, oc);
1891  }
1892  Unexpected(3);
1893
1894  if (L) {
1895    /* Because of the integer promotions, you must use a U after
1896       the MAX_CHARS in the following cases */
1897    if ((sizeof(char) == sizeof(int)) && !c_signed) {
1898      u_define(D_CHAR_MAX, "", "CHAR", "_MAX",
1899         (ulong) char_max,
1900         (ulong) CHAR_MAX, "");
1901    } else {
1902      i_define(D_CHAR_MAX, "", "CHAR", "_MAX",
1903         (long) char_max, 0L,
1904         (long) CHAR_MAX, "");
1905    }
1906    i_define(D_CHAR_MIN, "", "CHAR", "_MIN",
1907       (long) char_min, (long) maxint,
1908       (long) CHAR_MIN, "");
1909    if (c_signed) {
1910      i_define(D_SCHAR_MAX, "", "SCHAR", "_MAX",
1911         (long) char_max, 0L,
1912         (long) SCHAR_MAX, "");
1913      i_define(D_SCHAR_MIN, "", "SCHAR", "_MIN",
1914         (long) char_min, (long) maxint,
1915         (long) SCHAR_MIN, "");
1916    } else {
1917      if (sizeof(char) == sizeof(int)) {
1918        u_define(D_UCHAR_MAX, "", "UCHAR", "_MAX",
1919           (ulong) char_max,
1920           (ulong) UCHAR_MAX, "");
1921      } else {
1922        i_define(D_UCHAR_MAX, "", "UCHAR", "_MAX",
1923           (long) char_max, 0L,
1924           (long) UCHAR_MAX, "");
1925      }
1926    }
1927
1928    if (c_signed) {
1929#ifndef NO_UC
1930/* Syntax error? Define NO_UC */ Volatile unsigned char c1, char_max;
1931      c1=0; char_max=0;
1932      c1++;
1933      if (setjmp(lab)==0) { /* Yields char_max */
1934        while (c1>char_max) {
1935          char_max=c1;
1936          c1++;
1937        }
1938      }
1939      Unexpected(4);
1940      if (sizeof(char) == sizeof(int)) {
1941        u_define(D_UCHAR_MAX, "", "UCHAR", "_MAX",
1942           (ulong) char_max,
1943           (ulong) UCHAR_MAX, "");
1944      } else {
1945        i_define(D_UCHAR_MAX, "", "UCHAR", "_MAX",
1946           (long) char_max, 0L,
1947           (long) UCHAR_MAX, "");
1948      }
1949#endif
1950    } else {
1951#ifndef NO_SC
1952/* Syntax error? Define NO_SC */ Volatile signed char c1, char_max, char_min;
1953      c1=0; char_max=0;
1954      c1++;
1955      if (setjmp(lab)==0) { /* Yields char_max */
1956        while (c1>char_max) {
1957          char_max=c1;
1958          c1++;
1959        }
1960      }
1961      c1=0; char_min=0;
1962      c1--;
1963      if (setjmp(lab)==0) { /* Yields char_min */
1964        while (c1<char_min) {
1965          char_min=c1;
1966          c1--;
1967        }
1968      }
1969      Unexpected(5);
1970      i_define(D_SCHAR_MIN, "", "SCHAR", "_MIN",
1971         (long) char_min, (long) maxint,
1972         (long) SCHAR_MIN, "");
1973      i_define(D_SCHAR_MAX, "", "SCHAR", "_MAX",
1974         (long) char_max, 0L,
1975         (long) SCHAR_MAX, "");
1976#endif /* NO_SC */
1977    }
1978  }
1979  return byte_size;
1980}
1981
1982int basic( void )
1983{
1984  /* The properties of the basic types.
1985     Returns number of bits per sizeof unit */
1986  Volatile int byte_size;
1987  typedef int function ();
1988  int variable;
1989  char *cp; int *ip; function *fp;
1990  int *p, *q;
1991
1992  Vprintf("%sSIZES%s\n", co, oc);
1993  byte_size= cprop();
1994
1995  /* Shorts, ints and longs *****************************************/
1996  Vprintf("%sshort=%d int=%d long=%d float=%d double=%d bits %s\n",
1997    co,
1998    (int) sizeof(short)*byte_size,
1999    (int) sizeof(int)*byte_size,
2000    (int) sizeof(long)*byte_size,
2001    (int) sizeof(float)*byte_size,
2002    (int) sizeof(double)*byte_size, oc);
2003  if (stdc) {
2004    Vprintf("%slong double=%d bits%s\n",
2005      co, (int) sizeof(Long_double)*byte_size, oc);
2006  }
2007  Vprintf("%schar*=%d bits%s%s\n",
2008    co, (int)sizeof(char *)*byte_size,
2009    sizeof(char *)>sizeof(int)?" BEWARE! larger than int!":"",
2010    oc);
2011  Vprintf("%sint* =%d bits%s%s\n",
2012    co, (int)sizeof(int *)*byte_size,
2013    sizeof(int *)>sizeof(int)?" BEWARE! larger than int!":"",
2014    oc);
2015  Vprintf("%sfunc*=%d bits%s%s\n",
2016    co, (int)sizeof(function *)*byte_size,
2017    sizeof(function *)>sizeof(int)?" BEWARE! larger than int!":"",
2018    oc);
2019
2020  showtype("Type size_t is", sizeof(0));
2021#ifdef STDC
2022  showtype("Type wchar_t is", L'x');
2023#endif
2024
2025  /* Alignment constants ********************************************/
2026
2027#define alignment(TYPE) \
2028  ((long)((char *)&((struct{char c; TYPE d;}*)0)->d - (char *)0))
2029
2030  Vprintf("\n%sALIGNMENTS%s\n", co, oc);
2031
2032  Vprintf("%schar=%ld short=%ld int=%ld long=%ld%s\n",
2033    co,
2034    alignment(char), alignment(short),
2035    alignment(int), alignment(long),
2036    oc);
2037
2038  Vprintf("%sfloat=%ld double=%ld%s\n",
2039    co,
2040    alignment(float), alignment(double),
2041    oc);
2042
2043  if (stdc) {
2044    Vprintf("%slong double=%ld%s\n",
2045      co,
2046      alignment(Long_double),
2047      oc);
2048  }
2049  Vprintf("%schar*=%ld int*=%ld func*=%ld%s\n",
2050    co,
2051    alignment(char *), alignment(int *), alignment(function *),
2052    oc);
2053
2054  Vprintf("\n");
2055
2056  /* Ten little endians *********************************************/
2057
2058  endian(byte_size);
2059
2060  /* Pointers *******************************************************/
2061
2062  Vprintf("\n%sPROPERTIES OF POINTERS%s\n", co, oc);
2063  cp= (char *) &variable;
2064  ip= (int *) &variable;
2065  fp= (function *) &variable;
2066
2067  Vprintf("%sChar and int pointer formats ", co);
2068  if (memeq((char *) &cp, sizeof(cp), (char *) &ip, sizeof(ip))) {
2069    Vprintf("seem identical%s\n", oc);
2070  } else {
2071    Vprintf("are different%s\n", oc);
2072  }
2073  Vprintf("%sChar and function pointer formats ", co);
2074  if (memeq((char *) &cp, sizeof(cp), (char *) &fp, sizeof(fp))) {
2075    Vprintf("seem identical%s\n", oc);
2076  } else {
2077    Vprintf("are different%s\n", oc);
2078  }
2079
2080  if (V) {
2081    if ((VOID *)"abcd" == (VOID *)"abcd")
2082      printf("%sStrings are shared%s\n", co, oc);
2083    else printf("%sStrings are not shared%s\n", co, oc);
2084  }
2085
2086  p=0; q=0;
2087  showtype("Type ptrdiff_t is", p-q);
2088
2089  //if (setjmp(mlab) == 0) {
2090  //  variable= *p;
2091  //  Vprintf("%sBEWARE! Dereferencing NULL doesn't cause a trap%s\n",
2092  //    co, oc);
2093  //} else {
2094  //  Vprintf("%sDereferencing NULL causes a trap%s\n", co, oc);
2095  //}
2096  if (setjmp(mlab)!=0) croak(-2);
2097
2098  Vprintf("\n%sPROPERTIES OF INTEGRAL TYPES%s\n", co, oc);
2099
2100  sprop();
2101  iprop();
2102  lprop();
2103  usprop();
2104  uiprop();
2105  ulprop();
2106
2107  promotions();
2108
2109  Unexpected(6);
2110
2111  return byte_size;
2112}
2113
2114#else /* not PASS0 */
2115
2116#ifdef SEP
2117/* The global variables used by several passes */
2118extern jmp_buf lab;
2119extern int V, L, F, bugs, bits_per_byte;
2120extern int maxint, flt_radix, flt_rounds;
2121extern Volatile int trapped;
2122extern char co[], oc[];
2123extern char *f_rep();
2124extern Void trap1();
2125#endif /* SEP */
2126#endif /* ifdef PASS0 */
2127
2128/* As I said, I apologise for the contortions below. The functions are
2129   expanded by the preprocessor twice or three times (for float and double,
2130   and maybe for long double, and for short, int and long). That way,
2131   I never make a change to one that I forget to make to the other.
2132   You can look on it as C's fault for not supporting multi-line macros.
2133   This whole file is read 3 times by the preprocessor, with PASSn set for
2134   n=1, 2 or 3, to decide which parts to reprocess.
2135*/
2136
2137/* #undef on an already undefined thing is (wrongly) flagged as an error
2138   by some compilers, therefore the #ifdef that follows:
2139*/
2140#ifdef Number
2141#undef Number
2142#undef THING
2143#undef Thing
2144#undef thing
2145#undef FPROP
2146#undef Fname
2147#undef Store
2148#undef Sum
2149#undef Diff
2150#undef Mul
2151#undef Div
2152#undef ZERO
2153#undef HALF
2154#undef ONE
2155#undef TWO
2156#undef THREE
2157#undef FOUR
2158#undef Self
2159#undef F_check
2160#undef Verify
2161#undef EPROP
2162#undef MARK
2163
2164/* These are the float.h constants */
2165#undef F_RADIX
2166#undef F_MANT_DIG
2167#undef F_DIG
2168#undef F_ROUNDS
2169#undef F_EPSILON
2170#undef F_MIN_EXP
2171#undef F_MIN
2172#undef F_MIN_10_EXP
2173#undef F_MAX_EXP
2174#undef F_MAX
2175#undef F_MAX_10_EXP
2176#endif
2177
2178#ifdef Integer
2179#undef Integer
2180#undef INT
2181#undef IPROP
2182#undef Iname
2183#undef UPROP
2184#undef Uname
2185#undef OK_UI
2186#undef IMARK
2187
2188#undef I_MAX
2189#undef I_MIN
2190#undef U_MAX
2191#endif
2192
2193#ifdef PASS1
2194
2195/* Define the things we're going to use this pass */
2196
2197#define Number  float
2198#define THING "FLOAT"
2199#define Thing "Float"
2200#define thing "float"
2201#define Fname "FLT"
2202#define FPROP fprop
2203#define Store fStore
2204#define Sum fSum
2205#define Diff  fDiff
2206#define Mul fMul
2207#define Div fDiv
2208#define ZERO  0.0
2209#define HALF  0.5
2210#define ONE 1.0
2211#define TWO 2.0
2212#define THREE 3.0
2213#define FOUR  4.0
2214#define Self  fSelf
2215#define F_check fCheck
2216#define MARK  "F"
2217#ifdef VERIFY
2218#define Verify fVerify
2219#endif
2220
2221#define EPROP efprop
2222
2223#define Integer short
2224#define INT "short"
2225#define IPROP sprop
2226#define Iname "SHRT"
2227#ifndef NO_UI
2228#define OK_UI 1
2229#endif
2230#define IMARK ""
2231
2232#define UPROP usprop
2233#define Uname "USHRT"
2234
2235#ifdef VERIFY
2236#ifdef SHRT_MAX
2237#define I_MAX   SHRT_MAX
2238#endif
2239#ifdef SHRT_MIN
2240#define I_MIN   SHRT_MIN
2241#endif
2242#ifdef USHRT_MAX
2243#define U_MAX   USHRT_MAX
2244#endif
2245
2246#ifdef FLT_RADIX
2247#define F_RADIX   FLT_RADIX
2248#endif
2249#ifdef FLT_MANT_DIG
2250#define F_MANT_DIG  FLT_MANT_DIG
2251#endif
2252#ifdef FLT_DIG
2253#define F_DIG   FLT_DIG
2254#endif
2255#ifdef FLT_ROUNDS
2256#define F_ROUNDS  FLT_ROUNDS
2257#endif
2258#ifdef FLT_EPSILON
2259#define F_EPSILON FLT_EPSILON
2260#endif
2261#ifdef FLT_MIN_EXP
2262#define F_MIN_EXP FLT_MIN_EXP
2263#endif
2264#ifdef FLT_MIN
2265#define F_MIN   FLT_MIN
2266#endif
2267#ifdef FLT_MIN_10_EXP
2268#define F_MIN_10_EXP  FLT_MIN_10_EXP
2269#endif
2270#ifdef FLT_MAX_EXP
2271#define F_MAX_EXP FLT_MAX_EXP
2272#endif
2273#ifdef FLT_MAX
2274#define F_MAX   FLT_MAX
2275#endif
2276#ifdef FLT_MAX_10_EXP
2277#define F_MAX_10_EXP  FLT_MAX_10_EXP
2278#endif
2279#endif /* VERIFY */
2280
2281#endif /* PASS1 */
2282
2283#ifdef PASS2
2284
2285#define Number  double
2286#define THING "DOUBLE"
2287#define Thing "Double"
2288#define thing "double"
2289#define Fname "DBL"
2290#define FPROP dprop
2291#define Store dStore
2292#define Sum dSum
2293#define Diff  dDiff
2294#define Mul dMul
2295#define Div dDiv
2296#define ZERO  0.0
2297#define HALF  0.5
2298#define ONE 1.0
2299#define TWO 2.0
2300#define THREE 3.0
2301#define FOUR  4.0
2302#define Self  dSelf
2303#define F_check dCheck
2304#define MARK  ""
2305#ifdef VERIFY
2306#define Verify dVerify
2307#endif
2308
2309#define EPROP edprop
2310
2311#define Integer int
2312#define INT "int"
2313#define IPROP iprop
2314#define Iname "INT"
2315#define OK_UI 1 /* Unsigned int is always possible */
2316#define IMARK ""
2317
2318#define UPROP uiprop
2319#define Uname "UINT"
2320
2321#ifdef VERIFY
2322#ifdef INT_MAX
2323#define I_MAX   INT_MAX
2324#endif
2325#ifdef INT_MIN
2326#define I_MIN   INT_MIN
2327#endif
2328#ifdef UINT_MAX
2329#define U_MAX   UINT_MAX
2330#endif
2331
2332#ifdef DBL_MANT_DIG
2333#define F_MANT_DIG  DBL_MANT_DIG
2334#endif
2335#ifdef DBL_DIG
2336#define F_DIG   DBL_DIG
2337#endif
2338#ifdef DBL_EPSILON
2339#define F_EPSILON DBL_EPSILON
2340#endif
2341#ifdef DBL_MIN_EXP
2342#define F_MIN_EXP DBL_MIN_EXP
2343#endif
2344#ifdef DBL_MIN
2345#define F_MIN   DBL_MIN
2346#endif
2347#ifdef DBL_MIN_10_EXP
2348#define F_MIN_10_EXP  DBL_MIN_10_EXP
2349#endif
2350#ifdef DBL_MAX_EXP
2351#define F_MAX_EXP DBL_MAX_EXP
2352#endif
2353#ifdef DBL_MAX
2354#define F_MAX   DBL_MAX
2355#endif
2356#ifdef DBL_MAX_10_EXP
2357#define F_MAX_10_EXP  DBL_MAX_10_EXP
2358#endif
2359#endif /* VERIFY */
2360
2361#endif /* PASS2 */
2362
2363#ifdef PASS3
2364
2365#ifdef STDC
2366#define Number  long double
2367
2368#define ZERO  0.0L
2369#define HALF  0.5L
2370#define ONE 1.0L
2371#define TWO 2.0L
2372#define THREE 3.0L
2373#define FOUR  4.0L
2374#endif
2375
2376#define THING "LONG DOUBLE"
2377#define Thing "Long double"
2378#define thing "long double"
2379#define Fname "LDBL"
2380#define FPROP ldprop
2381#define Store ldStore
2382#define Sum ldSum
2383#define Diff  ldDiff
2384#define Mul ldMul
2385#define Div ldDiv
2386#define Self  ldSelf
2387#define F_check ldCheck
2388#define MARK  "L"
2389#ifdef VERIFY
2390#define Verify ldVerify
2391#endif
2392
2393#define EPROP eldprop
2394
2395#define Integer long
2396#define INT "long"
2397#define IPROP lprop
2398#define Iname "LONG"
2399#ifndef NO_UI
2400#define OK_UI 1
2401#endif
2402#define IMARK "L"
2403
2404#define UPROP ulprop
2405#define Uname "ULONG"
2406
2407#ifdef VERIFY
2408#ifdef LONG_MAX
2409#define I_MAX LONG_MAX
2410#endif
2411#ifdef LONG_MIN
2412#define I_MIN LONG_MIN
2413#endif
2414#ifdef ULONG_MAX
2415#define U_MAX ULONG_MAX
2416#endif
2417
2418#ifdef LDBL_MANT_DIG
2419#define F_MANT_DIG  LDBL_MANT_DIG
2420#endif
2421#ifdef LDBL_DIG
2422#define F_DIG   LDBL_DIG
2423#endif
2424#ifdef LDBL_EPSILON
2425#define F_EPSILON LDBL_EPSILON
2426#endif
2427#ifdef LDBL_MIN_EXP
2428#define F_MIN_EXP LDBL_MIN_EXP
2429#endif
2430#ifdef LDBL_MIN
2431#define F_MIN   LDBL_MIN
2432#endif
2433#ifdef LDBL_MIN_10_EXP
2434#define F_MIN_10_EXP  LDBL_MIN_10_EXP
2435#endif
2436#ifdef LDBL_MAX_EXP
2437#define F_MAX_EXP LDBL_MAX_EXP
2438#endif
2439#ifdef LDBL_MAX
2440#define F_MAX   LDBL_MAX
2441#endif
2442#ifdef LDBL_MAX_10_EXP
2443#define F_MAX_10_EXP  LDBL_MAX_10_EXP
2444#endif
2445#endif /* VERIFY */
2446
2447#endif /* PASS3 */
2448
2449/* The rest of the file gets read all three times;
2450   the differences are encoded in the things #defined above.
2451*/
2452
2453#ifndef I_MAX
2454#define I_MAX int_max
2455#endif
2456#ifndef I_MIN
2457#define I_MIN int_min
2458#endif
2459#ifndef U_MAX
2460#define U_MAX u_max
2461#endif
2462
2463#ifndef F_RADIX
2464#define F_RADIX   f_radix
2465#endif
2466#ifndef F_MANT_DIG
2467#define F_MANT_DIG  f_mant_dig
2468#endif
2469#ifndef F_DIG
2470#define F_DIG   f_dig
2471#endif
2472#ifndef F_ROUNDS
2473#define F_ROUNDS  f_rounds
2474#endif
2475#ifndef F_EPSILON
2476#define F_EPSILON f_epsilon
2477#endif
2478#ifndef F_MIN_EXP
2479#define F_MIN_EXP f_min_exp
2480#endif
2481#ifndef F_MIN
2482#define F_MIN   f_min
2483#endif
2484#ifndef F_MIN_10_EXP
2485#define F_MIN_10_EXP  f_min_10_exp
2486#endif
2487#ifndef F_MAX_EXP
2488#define F_MAX_EXP f_max_exp
2489#endif
2490#ifndef F_MAX
2491#define F_MAX   f_max
2492#endif
2493#ifndef F_MAX_10_EXP
2494#define F_MAX_10_EXP  f_max_10_exp
2495#endif
2496
2497#ifndef VERIFY
2498#define Verify(prec, val, req, same, same1) {;}
2499#endif
2500
2501#ifdef Integer
2502
2503Void IPROP( void )
2504{
2505  /* the properties of short, int, and long */
2506  Volatile Integer newi, int_max, maxeri, int_min, minneri;
2507  Volatile int ibits, ipower, two=2;
2508
2509  /* Calculate max short/int/long ***********************************/
2510  /* Calculate 2**n-1 until overflow - then use the previous value  */
2511
2512  newi=1; int_max=0;
2513
2514  if (setjmp(lab)==0) { /* Yields int_max */
2515    for(ipower=0; newi>int_max; ipower++) {
2516      int_max=newi;
2517      newi=newi*two+1;
2518    }
2519    Vprintf("%sOverflow of a%s %s does not generate a trap%s\n",
2520      co, INT[0]=='i'?"n":"", INT, oc);
2521  } else {
2522    Vprintf("%sOverflow of a%s %s generates a trap%s\n",
2523      co, INT[0]=='i'?"n":"", INT, oc);
2524  }
2525  Unexpected(7);
2526
2527  /* Minimum value: assume either two's or one's complement *********/
2528  int_min= -int_max;
2529  if (setjmp(lab)==0) { /* Yields int_min */
2530    if (int_min-1 < int_min) int_min--;
2531  }
2532  Unexpected(8);
2533
2534  /* Now for those daft Cybers */
2535
2536  maxeri=0; newi=int_max;
2537
2538  if (setjmp(lab)==0) { /* Yields maxeri */
2539    for(ibits=ipower; newi>maxeri; ibits++) {
2540      maxeri=newi;
2541      newi=newi+newi+1;
2542    }
2543  }
2544  Unexpected(9);
2545
2546  minneri= -maxeri;
2547  if (setjmp(lab)==0) { /* Yields minneri */
2548    if (minneri-1 < minneri) minneri--;
2549  }
2550  Unexpected(10);
2551
2552  Vprintf("%sMaximum %s = %ld (= 2**%d-1)%s\n",
2553    co, INT, (long)int_max, ipower, oc);
2554  Vprintf("%sMinimum %s = %ld%s\n", co, INT, (long)int_min, oc);
2555
2556  if (L) i_define(D_INT_MAX, INT, Iname, "_MAX",
2557      (long) int_max, 0L,
2558      (long) I_MAX, IMARK);
2559  if (L) i_define(D_INT_MIN, INT, Iname, "_MIN",
2560      (long) int_min, (long) (PASS==1?maxint:int_max),
2561      (long) I_MIN, IMARK);
2562
2563  if(int_max < 0) { /* It has happened (on a Cray) */
2564    eek_a_bug("signed integral comparison faulty?");
2565  }
2566
2567  if (maxeri>int_max) {
2568    Vprintf("%sThere is a larger %s, %ld (= 2**%d-1), %s %s%s\n",
2569      co, INT, (long)maxeri, ibits,
2570      "but only for addition, not multiplication",
2571      "(I smell a Cyber!)",
2572      oc);
2573  }
2574
2575  if (minneri<int_min) {
2576    Vprintf("%sThere is a smaller %s, %ld, %s %s%s\n",
2577      co, INT, (long)minneri,
2578      "but only for addition, not multiplication",
2579      "(I smell a Cyber!)",
2580      oc);
2581  }
2582}
2583
2584Void UPROP ( void )
2585{
2586  /* The properties of unsigned short/int/long */
2587#ifdef OK_UI
2588  Volatile unsigned Integer u_max, newi, two;
2589  newi=1; u_max=0; two=2;
2590
2591  if (setjmp(lab)==0) { /* Yields u_max */
2592    while(newi>u_max) {
2593      u_max=newi;
2594      newi=newi*two+1;
2595    }
2596  }
2597  Unexpected(11);
2598  Vprintf("%sMaximum unsigned %s = %lu%s\n",
2599    co, INT, (unsigned long) u_max, oc);
2600
2601  /* Oh woe: new standard C defines value preserving promotions:
2602     3.2.1.1: "If an int can represent all values of the original type,
2603           the value is converted to an int;
2604         otherwise it is converted to an unsigned int."
2605  */
2606  if (L) {
2607    if (PASS == 1 /* we're dealing with short */
2608        && u_max <= maxint /* an int can represent all values */
2609        )
2610    { /* the value is converted to an int */
2611      i_define(D_UINT_MAX, INT, Uname, "_MAX",
2612         (long) u_max, 0L,
2613         (long) U_MAX, IMARK);
2614    } else { /* it is converted to an unsigned int */
2615      u_define(D_UINT_MAX, INT, Uname, "_MAX",
2616         (unsigned long) u_max,
2617         (unsigned long) U_MAX, IMARK);
2618    }
2619  }
2620#endif
2621}
2622
2623#endif /* Integer */
2624
2625#ifdef Number
2626
2627/* The following routines are intended to defeat any attempt at optimisation
2628   or use of extended precision, and to defeat faulty narrowing casts.
2629   The weird prototypes are because of widening incompatibilities.
2630*/
2631#if defined(STDC) || defined(_MSC_VER)
2632#define ARGS1(A, a) (A a)
2633#define ARGS2(A, a, B, b) (A a, B b)
2634#define ARGS5(A, a, B, b, C, c, D, d, E, e) (A a, B b, C c, D d, E e)
2635#else
2636#define ARGS1(A, a) (a) A a;
2637#define ARGS2(A, a, B, b) (a, b) A a; B b;
2638#define ARGS5(A, a, B, b, C, c, D, d, E, e) (a,b,c,d,e)A a; B b; C c; D d; E e;
2639#endif
2640
2641Void Store ARGS2(Number, a, Number *, b) { *b=a; }
2642Number Sum ARGS2(Number, a, Number, b) {Number r; Store(a+b, &r); return r; }
2643Number Diff ARGS2(Number, a, Number, b){Number r; Store(a-b, &r); return r; }
2644Number Mul ARGS2(Number, a, Number, b) {Number r; Store(a*b, &r); return r; }
2645Number Div ARGS2(Number, a, Number, b) {Number r; Store(a/b, &r); return r; }
2646Number Self ARGS1(Number, a)         {Number r; Store(a,   &r); return r; }
2647
2648Void F_check ARGS((int precision, Long_double val1));
2649
2650Void F_check(int precision, Long_double val1)
2651{
2652  /* You don't think I'm going to go to all the trouble of writing
2653     a program that works out what all sorts of values are, only to
2654     have printf go and print the wrong values out, do you?
2655     No, you're right, so this function tries to see if printf
2656     has written the right value, by reading it back again.
2657     This introduces a new problem of course: suppose printf writes
2658     the correct value, and scanf reads it back wrong... oh well.
2659     But I'm adamant about this: the precision given is enough
2660     to uniquely identify the printed number, therefore I insist
2661     that sscanf read the number back identically. Harsh yes, but
2662     sometimes you've got to be cruel to be kind.
2663  */
2664  Long_double new1, rem;
2665  Number val, new, diff;
2666  int e;
2667  char *rep, *f2;
2668
2669  if (sizeof(double) == sizeof(Long_double)) {
2670    /* Assume they're the same, and use non-stdc format */
2671    /* This is for stdc compilers using non-stdc libraries */
2672    f2= "%le";   /* Input */
2673  } else {
2674    /* It had better support Le then */
2675    f2= "%Le";
2676  }
2677  val= (Number) val1;
2678  rep= f_rep(precision, (Long_double) val);
2679  if (setjmp(lab)==0) {
2680    sscanf(rep, f2, &new1);
2681  } else {
2682    eek_a_bug("sscanf caused a trap");
2683    printf("%s    scanning: %s format: %s%s\n\n", co, rep, f2, oc);
2684    Unexpected(12);
2685    return;
2686  }
2687
2688  if (setjmp(lab)==0) { /* See if new is usable */
2689    new= new1;
2690    if (new != 0.0) {
2691      diff= val/new - 1.0;
2692      if (diff < 0.1) diff= 1.0;
2693      /* That should be enough to generate a trap */
2694    }
2695  } else {
2696    eek_a_bug("sscanf returned an unusable number");
2697    printf("%s    scanning: %s with format: %s%s\n\n",
2698           co, rep, f2, oc);
2699    Unexpected(13);
2700    return;
2701  }
2702
2703  Unexpected(14);
2704  if (new != val) {
2705    eek_a_bug("Possibly bad output from printf above");
2706    if (!exponent((Long_double)val, &rem, &e)) {
2707      printf("%s    but value was an unusable number%s\n\n",
2708             co, oc);
2709      return;
2710    }
2711    printf("%s    expected value around ", co);
2712    //if (sizeof(double) == sizeof(Long_double)) {
2713      /* Assume they're the same, and use non-stdc format */
2714      /* This is for stdc compilers using non-stdc libraries */
2715      //printf("%.*fe%d, bit pattern:\n    ", precision, rem, e);
2716    //} else {
2717      /* It had better support Lfe then */
2718      printf("%.*Lfe%d, bit pattern:\n    ", precision, rem, e);
2719    //}
2720    bitpattern((char *) &val, (unsigned)sizeof(val));
2721    printf ("%s\n", oc);
2722    printf("%s    sscanf gave           %s, bit pattern:\n    ",
2723           co, f_rep(precision, (Long_double) new));
2724    bitpattern((char *) &new, (unsigned)sizeof(new));
2725    printf ("%s\n", oc);
2726    if (setjmp(lab) == 0) {
2727      diff= val-new;
2728      printf("%s    difference= %s%s\n\n",
2729             co, f_rep(precision, (Long_double) diff), oc);
2730    } /* else forget it */
2731    Unexpected(15);
2732  }
2733}
2734
2735#ifdef VERIFY
2736Void Verify ARGS5(int, prec, Number, val, Number, req, int, same, int, same1)
2737{
2738  /* Check that the compiler has read a #define value correctly */
2739  Unexpected(16);
2740  if (!same) {
2741    printf("%s*** Verify failed for above #define!\n", co);
2742    if (setjmp(lab) == 0) { /* for the case that req == nan */
2743      printf("       Compiler has %s for value\n",
2744             f_rep(prec, req));
2745    } else {
2746      printf("       Compiler has %s for value\n",
2747             "an unusable number");
2748    }
2749    if (setjmp(lab) == 0) {
2750      F_check(prec, (Long_double) req);
2751    } /*else forget it*/
2752    if (setjmp(lab) == 0) {
2753      if (req > 0.0 && val > 0.0) {
2754        printf("       difference= %s\n",
2755               f_rep(prec, val-req));
2756      }
2757    } /*else forget it*/
2758    Unexpected(17);
2759    printf("%s\n", oc);
2760    bugs++;
2761  } else if (!same1) {
2762    if (stdc) eek_a_bug("constant has the wrong precision");
2763    else eek_a_bug("the cast didn't work");
2764    printf("\n");
2765  }
2766}
2767#endif /* VERIFY */
2768
2769int FPROP(int byte_size)
2770{
2771  /* Properties of floating types, using algorithms by Cody and Waite
2772     from MA Malcolm, as modified by WM Gentleman and SB Marovich.
2773     Further extended by S Pemberton.
2774
2775     Returns the number of digits in the fraction.
2776  */
2777
2778  Volatile int
2779    i, f_radix, iexp, irnd, mrnd, f_rounds, f_mant_dig,
2780    iz, k, inf, machep, f_max_exp, f_min_exp, mx, negeps,
2781    mantbits, digs, f_dig, trap,
2782    hidden, normal, f_min_10_exp, f_max_10_exp;
2783  Volatile Number
2784    a, b, base, basein, basem1, f_epsilon, epsneg,
2785    eps, epsp1, etop, ebot,
2786    f_max, newxmax, f_min, xminner, y, y1, z, z1, z2;
2787
2788  Unexpected(18);
2789
2790  Vprintf("%sPROPERTIES OF %s%s\n", co, THING, oc);
2791
2792  /* Base and size of significand **************************************/
2793  /* First repeatedly double until adding 1 has no effect.    */
2794  /* For instance, if base is 10, with 3 significant digits   */
2795  /* it will try 1, 2, 4, 8, ... 512, 1024, and stop there,   */
2796  /* since 1024 is only representable as 1020.        */
2797  a=1.0;
2798  if (setjmp(lab)==0) { /* inexact trap? */
2799    do { a=Sum(a, a); }
2800    while (Diff(Diff(Sum(a, ONE), a), ONE) == ZERO);
2801  } else {
2802    fprintf(stderr, "*** Program got loss-of-precision trap!\n");
2803    /* And supporting those is just TOO much trouble! */
2804    farewell(bugs+1);
2805  }
2806  Unexpected(19);
2807  /* Now double until you find a number that can be added to the    */
2808  /* above number. For 1020 this is 8 or 16, depending whether the  */
2809  /* result is rounded or truncated.          */
2810  /* In either case the result is 1030. 1030-1020= the base, 10.    */
2811  b=1.0;
2812  do { b=Sum(b, b); } while ((base=Diff(Sum(a, b), a)) == ZERO);
2813  f_radix=base;
2814  Vprintf("%sBase = %d%s\n", co, f_radix, oc);
2815
2816  /* Sanity check; if base<2, I can't guarantee the rest will work  */
2817  if (f_radix < 2) {
2818    eek_a_bug("Function return or parameter passing faulty? (This is a guess.)");
2819    printf("\n");
2820    return(0);
2821  }
2822
2823  if (PASS == 1) { /* only for FLT */
2824    flt_radix= f_radix;
2825    if (F) i_define(D_FLT_RADIX, "", "FLT", "_RADIX",
2826        (long) f_radix, 0L, (long) F_RADIX, "");
2827  } else if (f_radix != flt_radix) {
2828    printf("\n%s*** WARNING: %s %s (%d) %s%s\n",
2829           co, thing, "arithmetic has a different radix",
2830           f_radix, "from float", oc);
2831    bugs++;
2832  }
2833
2834  /* Now the number of digits precision */
2835  f_mant_dig=0; b=1.0;
2836  do { f_mant_dig++; b=Mul(b, base); }
2837  while (Diff(Diff(Sum(b, ONE), b), ONE) == ZERO);
2838  f_dig=floor_log(10, (Long_double)(b/base)) + (base==10?1:0);
2839  Vprintf("%sSignificant base digits = %d %s %d %s%s\n",
2840    co, f_mant_dig, "(= at least", f_dig, "decimal digits)", oc);
2841  if (F) i_define(D_MANT_DIG, thing, Fname, "_MANT_DIG",
2842      (long) f_mant_dig, 0L, (long) F_MANT_DIG, "");
2843  if (F) i_define(D_DIG, thing, Fname, "_DIG",
2844      (long) f_dig, 0L, (long) F_DIG, "");
2845  digs= ceil_log(10, (Long_double)b); /* the number of digits to printf */
2846
2847  /* Rounding *******************************************************/
2848  basem1=Diff(base, HALF);
2849  if (Diff(Sum(a, basem1), a) != ZERO) {
2850    if (f_radix == 2) basem1=0.375;
2851    else basem1=1.0;
2852    if (Diff(Sum(a, basem1), a) != ZERO) irnd=2; /* away from 0 */
2853    else irnd=1; /* to nearest */
2854  } else irnd=0; /* towards 0 */
2855
2856  basem1=Diff(base, HALF);
2857
2858  if (Diff(Diff(-a, basem1), -a) != ZERO) {
2859    if (f_radix == 2) basem1=0.375;
2860    else basem1=1.0;
2861    if (Diff(Diff(-a, basem1), -a) != ZERO) mrnd=2; /* away from 0*/
2862    else mrnd=1; /* to nearest */
2863  } else mrnd=0; /* towards 0 */
2864
2865  f_rounds= -1; /* Unknown rounding */
2866  if (irnd==0 && mrnd==0) f_rounds=0; /* zero = chops */
2867  if (irnd==1 && mrnd==1) f_rounds=1; /* nearest */
2868  if (irnd==2 && mrnd==0) f_rounds=2; /* +inf */
2869  if (irnd==0 && mrnd==2) f_rounds=3; /* -inf */
2870
2871  if (f_rounds != -1) {
2872    Vprintf("%sArithmetic rounds towards ", co);
2873    switch (f_rounds) {
2874          case 0: Vprintf("zero (i.e. it chops)"); break;
2875          case 1: Vprintf("nearest"); break;
2876          case 2: Vprintf("+infinity"); break;
2877          case 3: Vprintf("-infinity"); break;
2878          default: Vprintf("???"); break;
2879    }
2880    Vprintf("%s\n", oc);
2881  } else { /* Hmm, try to give some help here */
2882    Vprintf("%sArithmetic rounds oddly: %s\n", co, oc);
2883    Vprintf("%s    Negative numbers %s%s\n",
2884      co, mrnd==0 ? "towards zero" :
2885          mrnd==1 ? "to nearest" :
2886              "away from zero",
2887      oc);
2888    Vprintf("%s    Positive numbers %s%s\n",
2889      co, irnd==0 ? "towards zero" :
2890          irnd==1 ? "to nearest" :
2891              "away from zero",
2892      oc);
2893  }
2894  /* An extra goody */
2895  if (f_radix == 2 && f_rounds == 1) {
2896    if (Diff(Sum(a, ONE), a) != ZERO) {
2897      Vprintf("%s   Tie breaking rounds up%s\n", co, oc);
2898    } else if (Diff(Sum(a, THREE), a) == FOUR) {
2899      Vprintf("%s   Tie breaking rounds to even%s\n", co, oc);
2900    } else {
2901      Vprintf("%s   Tie breaking rounds down%s\n", co, oc);
2902    }
2903  }
2904  if (PASS == 1) { /* only for FLT */
2905    flt_rounds= f_rounds;
2906    if (F)
2907      i_define(D_FLT_ROUNDS, "", "FLT", "_ROUNDS",
2908         (long) f_rounds, 1L, (long) F_ROUNDS, "");
2909  } else if (f_rounds != flt_rounds) {
2910    printf("\n%s*** WARNING: %s %s (%d) %s%s\n\n",
2911           co, thing, "arithmetic rounds differently",
2912           f_rounds, "from float", oc);
2913    bugs++;
2914  }
2915
2916  /* Various flavours of epsilon ************************************/
2917  negeps=f_mant_dig+f_mant_dig;
2918  basein=1.0/base;
2919  a=1.0;
2920  for(i=1; i<=negeps; i++) a*=basein;
2921
2922  b=a;
2923  while (Diff(Diff(ONE, a), ONE) == ZERO) {
2924    a*=base;
2925    negeps--;
2926  }
2927  negeps= -negeps;
2928  Vprintf("%sSmallest x such that 1.0-base**x != 1.0 = %d%s\n",
2929    co, negeps, oc);
2930
2931  etop = ONE;
2932  ebot = ZERO;
2933  eps = Sum(ebot, Div(Diff(etop, ebot), TWO));
2934  /* find the smallest epsneg (1-epsneg != 1) by binary search.
2935     ebot and etop are the current bounds */
2936  while (eps != ebot && eps != etop) {
2937    epsp1 = Diff(ONE, eps);
2938    if (epsp1 < ONE) etop = eps;
2939    else ebot = eps;
2940    eps = Sum(ebot, Div(Diff(etop, ebot), TWO));
2941  }
2942  eps= etop;
2943  /* Sanity check */
2944  if (Diff(ONE, etop) >= ONE || Diff(ONE, ebot) != ONE) {
2945    eek_a_bug("internal error calculating epsneg");
2946  }
2947  Vprintf("%sSmallest x such that 1.0-x != 1.0 = %s%s\n",
2948    co, f_rep(digs, (Long_double) eps), oc);
2949  if (V) F_check(digs, (Long_double) eps);
2950
2951  epsneg=a;
2952  if ((f_radix!=2) && irnd) {
2953  /*  a=(a*(1.0+a))/(1.0+1.0); => */
2954    a=Div(Mul(a, Sum(ONE, a)), Sum(ONE, ONE));
2955  /*  if ((1.0-a)-1.0 != 0.0) epsneg=a; => */
2956    if (Diff(Diff(ONE, a), ONE) != ZERO) epsneg=a;
2957  }
2958  /* epsneg is used later */
2959  Unexpected(20);
2960
2961  machep= -f_mant_dig-f_mant_dig;
2962  a=b;
2963  while (Diff(Sum(ONE, a), ONE) == ZERO) { a*=base; machep++; }
2964  Vprintf("%sSmallest x such that 1.0+base**x != 1.0 = %d%s\n",
2965    co, machep, oc);
2966
2967  etop = ONE;
2968  ebot = ZERO;
2969  eps = Sum(ebot, Div(Diff(etop, ebot), TWO));
2970  /* find the smallest eps (1+eps != 1) by binary search.
2971     ebot and etop are the current bounds */
2972  while (eps != ebot && eps != etop) {
2973    epsp1 = Sum(ONE, eps);
2974    if (epsp1 > ONE) etop = eps;
2975    else ebot = eps;
2976    eps = Sum(ebot, Div(Diff(etop, ebot), TWO));
2977  }
2978  /* Sanity check */
2979  if (Sum(ONE, etop) <= ONE || Sum(ONE, ebot) != ONE) {
2980    eek_a_bug("internal error calculating eps");
2981  }
2982  f_epsilon=etop;
2983
2984  Vprintf("%sSmallest x such that 1.0+x != 1.0 = %s%s\n",
2985    co, f_rep(digs, (Long_double) f_epsilon), oc);
2986
2987  f_epsilon= Diff(Sum(ONE, f_epsilon), ONE); /* New C standard defn */
2988  Vprintf("%s(Above number + 1.0) - 1.0 = %s%s\n",
2989    co, f_rep(digs, (Long_double) (f_epsilon)), oc);
2990
2991  /* Possible loss of precision warnings here from non-stdc compilers */
2992  if (F) f_define(D_EPSILON, thing,
2993      Fname, "_EPSILON", digs, (Long_double) f_epsilon, MARK);
2994  if (V || F) F_check(digs, (Long_double) f_epsilon);
2995  Unexpected(21);
2996  if (F) Verify(digs, f_epsilon, F_EPSILON,
2997          f_epsilon == Self(F_EPSILON),
2998          (Long_double) f_epsilon == (Long_double) F_EPSILON);
2999  Unexpected(22);
3000
3001  /* Extra chop info *************************************************/
3002  if (f_rounds == 0) {
3003    if (Diff(Mul(Sum(ONE,f_epsilon),ONE),ONE) !=  ZERO) {
3004      Vprintf("%sAlthough arithmetic chops, it uses guard digits%s\n", co, oc);
3005    }
3006  }
3007
3008  /* Size of and minimum normalised exponent ************************/
3009  y=0; i=0; k=1; z=basein; z1=(1.0+f_epsilon)/base;
3010
3011  /* Coarse search for the largest power of two */
3012  if (setjmp(lab)==0) { /* for underflow trap */ /* Yields i, k, y, y1 */
3013    do {
3014      y=z; y1=z1;
3015      z=Mul(y,y); z1=Mul(z1, y);
3016      a=Mul(z,ONE);
3017      z2=Div(z1,y);
3018      if (z2 != y1) break;
3019      if ((Sum(a,a) == ZERO) || (fabs(z) >= y)) break;
3020      i++;
3021      k+=k;
3022    } while(1);
3023  } else {
3024    Vprintf("%s%s underflow generates a trap%s\n", co, Thing, oc);
3025  }
3026  Unexpected(23);
3027
3028  if (f_radix != 10) {
3029    iexp=i+1; /* for the sign */
3030    mx=k+k;
3031  } else {
3032    iexp=2;
3033    iz=f_radix;
3034    while (k >= iz) { iz*=f_radix; iexp++; }
3035    mx=iz+iz-1;
3036  }
3037
3038  /* Fine tune starting with y and y1 */
3039  if (setjmp(lab)==0) { /* for underflow trap */ /* Yields k, f_min */
3040    do {
3041      f_min=y; z1=y1;
3042      y=Div(y,base); y1=Div(y1,base);
3043      a=Mul(y,ONE);
3044      z2=Mul(y1,base);
3045      if (z2 != z1) break;
3046      if ((Sum(a,a) == ZERO) || (fabs(y) >= f_min)) break;
3047      k++;
3048    } while (1);
3049  }
3050  Unexpected(24);
3051
3052  f_min_exp=(-k)+1;
3053
3054  if ((mx <= k+k-3) && (f_radix != 10)) { mx+=mx; iexp+=1; }
3055  Vprintf("%sNumber of bits used for exponent = %d%s\n", co, iexp, oc);
3056  Vprintf("%sMinimum normalised exponent = %d%s\n", co, f_min_exp-1, oc);
3057  if (F)
3058    i_define(D_MIN_EXP, thing, Fname, "_MIN_EXP",
3059       (long) f_min_exp, (long) maxint, (long) F_MIN_EXP, "");
3060
3061  if (setjmp(lab)==0) {
3062    Vprintf("%sMinimum normalised positive number = %s%s\n",
3063      co, f_rep(digs, (Long_double) f_min), oc);
3064  } else {
3065    eek_a_bug("printf can't print the smallest normalised number");
3066    printf("\n");
3067  }
3068  Unexpected(25);
3069  /* Possible loss of precision warnings here from non-stdc compilers */
3070  if (setjmp(lab) == 0) {
3071    if (F) f_define(D_MIN, thing,
3072        Fname, "_MIN", digs, (Long_double) f_min, MARK);
3073    if (V || F) F_check(digs, (Long_double) f_min);
3074  } else {
3075    eek_a_bug("xxx_MIN caused a trap");
3076    printf("\n");
3077  }
3078
3079  if (setjmp(lab) == 0) {
3080    if (F) Verify(digs, f_min, F_MIN,
3081            f_min == Self(F_MIN),
3082            (Long_double) f_min == (Long_double) F_MIN);
3083  } else {
3084    printf("%s*** Verify failed for above #define!\n    %s %s\n\n",
3085           co, "Compiler has an unusable number for value", oc);
3086    bugs++;
3087  }
3088  Unexpected(26);
3089
3090  a=1.0; f_min_10_exp=0;
3091  while (a > f_min*10.0) { a/=10.0; f_min_10_exp--; }
3092  if (F) i_define(D_MIN_10_EXP, thing, Fname, "_MIN_10_EXP",
3093      (long) f_min_10_exp, (long) maxint,
3094      (long) F_MIN_10_EXP, "");
3095
3096  /* Minimum exponent ************************************************/
3097  if (setjmp(lab)==0) { /* for underflow trap */ /* Yields xminner */
3098    do {
3099      xminner=y;
3100      y=Div(y,base);
3101      a=Mul(y,ONE);
3102      if ((Sum(a,a) == ZERO) || (fabs(y) >= xminner)) break;
3103    } while (1);
3104  }
3105  Unexpected(27);
3106
3107  if (xminner != 0.0 && xminner != f_min) {
3108    normal= 0;
3109    Vprintf("%sThe smallest numbers are not kept normalised%s\n",
3110      co, oc);
3111    if (setjmp(lab)==0) {
3112        Vprintf("%sSmallest unnormalised positive number = %s%s\n",
3113          co, f_rep(digs, (Long_double) xminner), oc);
3114        if (V) F_check(digs, (Long_double) xminner);
3115    } else {
3116      eek_a_bug("printf can't print the smallest unnormalised number.");
3117      printf("\n");
3118    }
3119    Unexpected(28);
3120  } else {
3121    normal= 1;
3122    Vprintf("%sThe smallest numbers are normalised%s\n", co, oc);
3123  }
3124
3125  /* Maximum exponent ************************************************/
3126  f_max_exp=2; f_max=1.0; newxmax=base+1.0;
3127  inf=0; trap=0;
3128  while (f_max<newxmax) {
3129    f_max=newxmax;
3130    if (setjmp(lab) == 0) { /* Yields inf, f_max_exp */
3131      newxmax=Mul(newxmax, base);
3132    } else {
3133      trap=1;
3134      break;
3135    }
3136    if (Div(newxmax, base) != f_max) {
3137      if (newxmax > f_max) inf=1; /* ieee infinity */
3138      break;
3139    }
3140    f_max_exp++;
3141  }
3142  Unexpected(29);
3143  Vprintf("%sMaximum exponent = %d%s\n", co, f_max_exp, oc);
3144  if (F) i_define(D_MAX_EXP, thing, Fname, "_MAX_EXP",
3145      (long) f_max_exp, 0L, (long) F_MAX_EXP, "");
3146
3147  /* Largest number ***************************************************/
3148  f_max=Diff(ONE, epsneg);
3149  if (Mul(f_max,ONE) != f_max) f_max=Diff(ONE, Mul(base,epsneg));
3150  for (i=1; i<=f_max_exp; i++) f_max=Mul(f_max, base);
3151
3152  if (setjmp(lab)==0) {
3153    Vprintf("%sMaximum number = %s%s\n",
3154      co, f_rep(digs, (Long_double) f_max), oc);
3155  } else {
3156    eek_a_bug("printf can't print the largest double.");
3157    printf("\n");
3158  }
3159  if (setjmp(lab)==0) {
3160  /* Possible loss of precision warnings here from non-stdc compilers */
3161    if (F) f_define(D_MAX, thing,
3162        Fname, "_MAX", digs, (Long_double) f_max, MARK);
3163    if (V || F) F_check(digs, (Long_double) f_max);
3164  } else {
3165    eek_a_bug("xxx_MAX caused a trap");
3166    printf("\n");
3167  }
3168  if (setjmp(lab)==0) {
3169    if (F) Verify(digs, f_max, F_MAX,
3170            f_max == Self(F_MAX),
3171            (Long_double) f_max == (Long_double) F_MAX);
3172  } else {
3173    printf("%s*** Verify failed for above #define!\n    %s %s\n\n",
3174           co, "Compiler has an unusable number for value", oc);
3175    bugs++;
3176  }
3177  Unexpected(30);
3178
3179  a=1.0; f_max_10_exp=0;
3180  while (a < f_max/10.0) { a*=10.0; f_max_10_exp++; }
3181  if (F) i_define(D_MAX_10_EXP, thing, Fname, "_MAX_10_EXP",
3182      (long) f_max_10_exp, 0L, (long) F_MAX_10_EXP, "");
3183
3184  /* Traps and infinities ********************************************/
3185  if (trap) {
3186    Vprintf("%sOverflow generates a trap%s\n", co, oc);
3187  } else {
3188    Vprintf("%sOverflow doesn't seem to generate a trap%s\n",
3189      co, oc);
3190  }
3191
3192  if (inf) { Vprintf("%sThere is an 'infinite' value%s\n", co, oc); }
3193
3194#ifdef SIGFPE
3195  signal(SIGFPE, trap1);
3196#endif
3197  if (setjmp(lab) == 0) {
3198    trapped= 0; /* A global variable */
3199    b= 0.0;
3200    a= (1.0/b)/b;
3201    if (!trapped) {
3202      Vprintf("%sDivide by zero doesn't generate a trap%s\n",
3203        co, oc);
3204    } else {
3205      Vprintf("%sDivide by zero generates a trap%s\n",
3206        co, oc);
3207      Vprintf("%sFP signal handlers return safely%s\n",
3208        co, oc);
3209    }
3210  } else {
3211    Vprintf("%sDivide by zero generates a trap%s\n", co, oc);
3212    Vprintf("%sBEWARE! FP signal handlers can NOT return%s\n",
3213      co, oc);
3214  }
3215  setsignals();
3216  Unexpected(31);
3217
3218  /* Hidden bit + sanity check ****************************************/
3219  if (f_radix != 10) {
3220    hidden=0;
3221    mantbits=floor_log(2, (Long_double)f_radix)*f_mant_dig;
3222    if (mantbits+iexp == (int)sizeof(Number)*byte_size) {
3223      hidden=1;
3224      Vprintf("%sArithmetic uses a hidden bit%s\n", co, oc);
3225    } else if (mantbits+iexp+1 == (int)sizeof(Number)*byte_size) {
3226      Vprintf("%sArithmetic doesn't use a hidden bit%s\n",
3227        co, oc);
3228    } else if (mantbits+iexp+1 < (int)sizeof(Number)*byte_size) {
3229      Vprintf("%sOnly %d of the %d bits of a %s %s%s\n",
3230        co,
3231        mantbits+iexp,
3232        (int)sizeof(Number)*byte_size,
3233        thing,
3234        "are actually used",
3235        oc);
3236    } else {
3237      printf("\n%s%s\n    %s (%d) %s (%d) %s %s (%d)!%s\n\n",
3238             co,
3239             "*** Something fishy here!",
3240             "Exponent size",
3241             iexp,
3242             "+ significand size",
3243             mantbits,
3244             "doesn't match with the size of a",
3245             thing,
3246             (int)sizeof(Number)*byte_size,
3247             oc);
3248    }
3249    if (hidden && f_radix == 2 && f_max_exp+f_min_exp==3) {
3250      Vprintf("%sIt looks like %s length IEEE format%s\n",
3251        co, f_mant_dig==24 ? "single" :
3252            f_mant_dig==53 ? "double" :
3253            f_mant_dig >53 ? "extended" :
3254            "some", oc);
3255      if (f_rounds != 1 || normal) {
3256        Vprintf("%s   though ", co);
3257        if (f_rounds != 1) {
3258          Vprintf("the rounding is unusual");
3259          if (normal) { Vprintf(" and "); }
3260        }
3261        if (normal) {
3262            Vprintf("the normalisation is unusual");
3263        }
3264        Vprintf("%s\n", oc);
3265      }
3266    } else {
3267      Vprintf("%sIt doesn't look like IEEE format%s\n",
3268        co, oc);
3269    }
3270  }
3271  printf("\n"); /* regardless of verbosity */
3272  return f_mant_dig;
3273}
3274
3275Void EPROP(int fprec, int dprec, int lprec)
3276{
3277  /* See if expressions are evaluated in extended precision.
3278     Some compilers optimise even if you don't want it,
3279     and then this function fails to produce the right result.
3280     We try to diagnose this if it happens.
3281  */
3282  Volatile int eprec;
3283  Volatile double a, b, base, old;
3284  Volatile Number d, oldd, dbase, one, zero;
3285  Volatile int bad=0;
3286
3287  /* Size of significand **************************************/
3288  a=1.0;
3289  if (setjmp(lab) == 0) { /* Yields nothing */
3290    do { old=a; a=a+a; }
3291    while ((((a+1.0)-a)-1.0) == 0.0 && a>old);
3292  } else bad=1;
3293  if (!bad && a <= old) bad=1;
3294
3295  if (!bad) {
3296    b=1.0;
3297    if (setjmp(lab) == 0) { /* Yields nothing */
3298      do { old=b; b=b+b; }
3299      while ((base=((a+b)-a)) == 0.0 && b>old);
3300      if (b <= old) bad=1;
3301    } else bad=1;
3302  }
3303
3304  if (!bad) {
3305    eprec=0; d=1.0; dbase=base; one=1.0; zero=0.0;
3306    if (setjmp(lab) == 0) { /* Yields nothing */
3307      do { eprec++; oldd=d; d=d*dbase; }
3308      while ((((d+one)-d)-one) == zero && d>oldd);
3309      if (d <= oldd) bad=1;
3310    } else bad=1;
3311  }
3312
3313  Unexpected(32);
3314
3315  if (bad) {
3316    Vprintf("%sCan't determine precision for %s expressions:\n%s%s\n",
3317     co, thing, "   check that you compiled without optimisation!",
3318     oc);
3319  } else if (eprec==dprec) {
3320    Vprintf("%s%s expressions are evaluated in double precision%s\n",
3321      co, Thing, oc);
3322  } else if (eprec==fprec) {
3323    Vprintf("%s%s expressions are evaluated in float precision%s\n",
3324      co, Thing, oc);
3325  } else if (eprec==lprec) {
3326    Vprintf("%s%s expressions are evaluated in long double precision%s\n",
3327      co, Thing, oc);
3328  } else {
3329    Vprintf("%s%s expressions are evaluated in a %s %s %d %s%s\n",
3330      co, Thing, eprec>dprec ? "higher" : "lower",
3331      "precision than double,\n   using",
3332      eprec, "base digits",
3333      oc);
3334  }
3335}
3336
3337#else /* not Number */
3338
3339#ifdef FPROP /* Then create dummy routines for long double */
3340/* ARGSUSED */
3341int FPROP(int byte_size) { return 0; }
3342#endif
3343#ifdef EPROP
3344/* ARGSUSED */
3345Void EPROP(int fprec, int dprec, int lprec) {}
3346#endif
3347
3348#endif /* ifdef Number */
3349
3350/* Increment the pass number */
3351#undef PASS
3352
3353#ifdef PASS2
3354#undef PASS2
3355#define PASS 3
3356#define PASS3 1
3357#endif
3358
3359#ifdef PASS1
3360#undef PASS1
3361#define PASS 2
3362#define PASS2 1
3363#endif
3364
3365#ifdef PASS0
3366#undef PASS0
3367#endif
3368
3369#ifndef SEP
3370#ifdef PASS /* then rescan this file */
3371#ifdef BAD_CPP
3372#include "enquire.c"
3373#else
3374#include FILENAME  /* if this line fails to compile, define BAD_CPP */
3375#endif
3376#endif /* PASS */
3377#endif /* SEP */
3378