#if __TCPLUSPLUS__ || __STDC__
# define __NSTDC__  1
#endif

/* ---------------------------------------------------------------------- */
/*                   Copyright (C) 1991 by Natuerlich!                    */
/*                      This file is copyrighted!                         */
/*                Refer to the documentation for details.                 */
/* ---------------------------------------------------------------------- */
/* compile and run this file TWICE                                   */
/* Littleendian means  $12345678 -> 12 34 56 78                      */
/* Bigendian    means  $12345678 -> 78 56 34 12                      */
/* this is stylistically pretty outdated, yet helpful                */
#define HAVEFUN   0     /* to test your compiler a bit more set to 1 */
                        /* » <-- Error ??  (see EOF)                 */
#define PHILOSOPHICAL_PROBLEM    1

#define IOCHECK   1
#define SIGNAL    1        /* MS-C does not define SIGSEGV properly */
#define STRICT    0
#define STDIO     <stdio.h>

#if ! __NSTDC__
# define signed
#endif

#ifdef TOS
# define OS               1
#else
# ifdef MSDOS
#  define OS              2
# else
#  ifdef UNIX
#   define OS             3
#  else
#   define OS            -1       /* unknown OS */
#  endif
# endif
#endif

#ifdef TOS
# undef TOS
#endif
#define TOS               1
#ifdef MSDOS
# undef MSDOS
#endif
#define MSDOS             2
#ifdef UNIX
# undef UNIX
#endif
#define UNIX              3
#ifdef UNKNOWN
# undef UNKNOWN
#endif
#define UNKNOWN          -1

#if OS == TOS
# define Fkreate( p, m)    Fcreate( p, 0)
# define Perror( s)
# if __TURBOC__
#   include <tos.h>
#  else
#   include <osbind.h>
# endif
# define OPEN_W      0
# define OPEN_R      1
# define OPEN_RW     2
# define fbyte_t     long
#else
# include "xosbind.h"
# if OS == MSDOS
#  define Perror( s)
#  ifdef OPEN_W
#   undef OPEN_W
#   undef OPEN_R
#   undef OPEN_RW
#  endif
#  define OPEN_W     O_WRONLY
#  define OPEN_R     O_RDONLY
#  define OPEN_RW    O_RDWR
#  define fbyte_t    long
# endif
# if OS == UNIX
#  include <string.h>
#  define Perror( s) perror( s)
#  ifdef OPEN_W
#   undef OPEN_W
#   undef OPEN_R
#   undef OPEN_RW
#  endif
#  define OPEN_W     O_WRONLY
#  define OPEN_R     O_RDONLY
#  define OPEN_RW    O_RDWR
#  define fbyte_t    unsigned
# endif
# if OS == UNKNOWN
#  define Perror( s)
#  define OPEN_W     1
#  define OPEN_R     0
#  define OPEN_RW    2
#  define fbyte_t    unsigned int
# endif
#endif

#include <stddef.h>
#include STDIO          /* Error ? not too bad, reedit OSBINDs in NASM */
#include <errno.h>


#if __TURBOC__
#  pragma warn -rvl     /* instead of very pretty                      */
#  pragma warn -pia     /* Don't want those if( foo = bar) warnings    */
#  pragma warn -pro     /* Also we don't care about prototypes anymore */
#  pragma warn +sig     /* (used to, but that's all over now)          */
#  pragma warn +use
#  pragma warn +stv
#  pragma warn +amb
#  pragma warn +amp
#endif

#if OS == TOS
typedef long   off_t;
#endif

#if SIGNAL
# include <signal.h>
# if OS == UNIX || OS == UNKNOWN || defined( __GNUC__)
#  define SIGADR   SIGBUS
# else
#  if OS == MSDOS
#   define SIGADR   SIGSEGV
#  endif
# endif
#endif

#if __TURBOC__ && OS == TOS
# include <ext.h>
#endif

#if OS == MSDOS
# include <fcntl.h>
# include <sys\stat.h>
#endif

#if OS == UNIX
# include <unistd.h>
#else
# if OS == TOS || OS == MSDOS
#  define SEEK_SET 0
#  define SEEK_CUR 1
#  define SEEK_END 2
# endif
#endif

#include "localdef.h"

/* ---------- FROM HERE ON EVERYTHING SHOULD WORK ---------- */
#define byte   unsigned _BYTE
#define word   unsigned _WORD
#define lword  unsigned _LONG
#define sbyte  signed   _BYTE
#define sword  signed   _WORD
#define slword signed   _LONG

#define WRITE( s)   fprintf( stderr, s)

/* HP cc can't take this (bastard compiler) so comment it out */
/* Sun cc doesn't cope either */

/*
#if __NSTDC__
# undef FOO
# define FOO 1
# ifndef FOO
#  error "Compiler can not handle #define/#undef properly"
# endif
# if ! FOO
#  error "That should not have happened"
# endif
# ifdef BAR
#  error "Throw your compiler away"
# endif
# undef FOO
# ifdef FOO
#  error "Compiler can not handle #define/#undef properly"
# endif
#endif
*/

/* till here */

#undef FOO
#if __NSTDC__
# define FOO( a, b, c)  a ## b ## c
# define BAR( a, b, c)  a##b##c
# define BAZ( a, b, c)  a/**/b/**/c
#else
# define FOO( a, b, c)  a/**/b/**/c
#endif

FILE  *fp, *fopen();
int   (*sdf)();


#if ! HAVEFUN || __NSTDC__
int   even;
#else
      even;          /* Just for fun. This is same as int even; and */
                     /* shouldn't give an error                     */
#endif

#if __NSTDC__
# if SIGNAL
void          dofoo( int);
# endif
extern void   exit( int);
void          xcontinue( int);
#else
void          xcontinue();
#endif


#if SIGNAL
void dofoo( foo)
{
   if( foo == SIGADR)         /* One less warning */
      WRITE( "WORDs must lie on an even address\n");
   else
      WRITE( "FUN! Signal out of nowhere\n");
   even++;
   xcontinue(0);
}
#endif

#if ! HAVEFUN
struct bar
{
   lword  a;
   word   b;
   byte  c;
} fx = { 0x55AACC33L, 0x5AC3, 0x5A };
#endif

word     x = 0x8000, y;
word     i;
byte     c = 0x80,
         *p,
         *q;
lword    bar;
sbyte    *foo;

void xcontinue( fd)
{
#if SIGNAL
   if( ! fd)
   {
      if( ! even)
      {
         WRITE( "WORD access on odd address is OK!\n");
         fprintf( fp, "#ifndef WORD_EVEN\n#define WORD_EVEN 0\n#endif\n\n");
      }
      else
         fprintf( fp, "#ifndef WORD_EVEN\n#define WORD_EVEN 1\n#endif\n\n");
      fclose( fp);

      if( signal( SIGADR, (void (*)()) sdf) == SIG_ERR)
         WRITE( "More fun w/SIGNAL\n");
   }
#endif
#if IOCHECK
# if OS == MSDOS
   _fmode = O_BINARY;
# endif
   {
#if HAVEFUN
      struct bar           /* Loser compilers will throw up on this. */
      {                    /* try a static if you like here as well  */
         lword  a;
         word   b;
         byte  c;
      } fx = { 0x55AACC33L, 0x5AC3, 0x5A };
#endif
      byte  y;
      lword  z;

      if( (fd = (int) Fkreate("foo.foo", 0644)) < 0)
      {
         WRITE( "Why did the creat fail ?\n");
         Perror( "hint:");
         goto fuckthis;
      }
      close( fd);
fuckthis:
      if( (fd = (int) Fopen("foo.foo", OPEN_W)) < 0)
      {
         WRITE( "Couldn't open foo.foo for writing.. WHY??\n");
         Perror( "hint:");
         goto fuckoff;
      }
      if( Fwrite( fd, (fbyte_t) sizeof( struct bar), &fx) !=
          (fbyte_t) sizeof( struct bar))
      {
         WRITE( "Didn't write correct number of bytes. Mighty peculiar\n");
         goto fuckoff;
      }
      close( fd);
      if( (fd = (int) Fopen("foo.foo", OPEN_R)) < 0)
      {
         WRITE( "Couldn't open foo.foo for reading. Bastard machinery!!\n");
         Perror( "hint:");
         goto fuckoff;
      }
      lseek( fd, (long) 6, SEEK_SET);
      if( Fread( fd, sizeof( byte), &y) != sizeof( byte))
         WRITE( "lseek went the wrong way\n");
      if( y != fx.c)
         WRITE( "Probably lseek incompatibility or structs are\
 higgledy-piggledy [FUN!]\n");

      lseek( fd, (long) -7, SEEK_CUR);
      if( Fread( fd, sizeof( lword), &z) != sizeof( lword))
         WRITE( "lseek incompatibility, can't index negatively\n");
      if( z != fx.a)
         WRITE( "Too strange to explain\n");
      close( fd);
   }
#endif
fuckoff:
   bar = (lword) foo;
   if( ! bar)
      WRITE( "Strange conversion problems\n");
#if SIGNAL
   WRITE( "If portable crashes in 10 seconds it doesn't matter\n");
# if __TURBOC__ && ! __PUREC__
   WRITE("It mosty probably will, thanx to TURBO.C");
# endif   
   {
      sword   i = 10;

      while( i--)
      {
         sleep( 1);
         fputc( '.', stderr);
         fflush( stderr);
      }
      fputc( '\n', stderr);
   }
#endif
   exit( 0);
}


main( argc, argv)
sbyte  **argv;
{
   fp  = stdout;    /* done her 'coz of some Amiga cc's lameness */
   i   = x;
   p   = (byte *) &i,
   q   = (byte *) &x;
   foo = (sbyte *) p;

   if( argc != 1)
      if( ! (fp = fopen("localdef.h", "w")))
      {
         WRITE( "Sorry couldn't open \"localdef.h\"\n");
         exit(1);
      }

   sdf = (int (*)()) main;
   if( (sword) i > 0 || (sbyte) c > 0)
   {
      WRITE( "ERROR: Machine/compiler doesn't use 2's complement\
. Don't worry about this\n the first time.");
   }

   for( i = 0; i < 256; i++)
      if( (c = i) != i)
         WRITE( "ERROR: Most probably chars are just 7 bits\n");

   c = i;
   if( c)
      WRITE( "ERROR: chars are longer than 8 bit (or abnormal)\n");

   y = 2;
   i = 1;
   x = FOO( y-,--i,-1);
   if( x)
#if ! __NSTDC__
      fprintf( fp, "#ifndef CANCONCAT\n#define CANCONCAT 2\n#endif\n\n");
   else
      WRITE( "Comments can't be used to concatenate (impossible to port)\n");
#else
   {
      WRITE( "Compiler can't concatenate token ## token\n");
      y = 2;
      i = 1;
      x = BAR( y-,--i,-1);
      if( x)
      {
         WRITE( "and can't concatenate text##text as well\n");
         y = 2;
         i = 1;
         x = BAZ( y-,--i,-1);
         if( x)
            WRITE( "Even text/**/text doesn't work (impossible to port)\n");
         else
         {
            WRITE( "but text/**/text does it <PHHHEWWWW!>\n");
            fprintf( fp, "#ifndef CANCONCAT\n#define CANCONCAT 0\n#endif\n\n");
         }
      }
      WRITE( "but text##text works <phew>\n");
      fprintf( fp, "#ifndef CANCONCAT\n#define CANCONCAT 1\n#endif\n\n");
   }
   else
   {
      WRITE( "Compiler likes to concatenate with text ## text\n");
      x = 3;
      x = BAR( x-,--1,-1);
      if( x)
      {
         WRITE( "But it can't concatenate text##text (which NASM uses)\n");
         i = 1;
         x = 3;
         x = BAZ( x-,--i,-1);
         if( x)
         {
            WRITE( "And text/**/text doesn't work either. You should set\n\
-DSUN in the CFLAGS definition of \"makefile.nix\"\n");
            putc( 7, stderr);
            fflush( stderr);
            sleep( 5);
         }
         else
         {
            WRITE( "But text/**/text does it <PHHHEWWWW!>\n");
            fprintf( fp, "#ifndef CANCONCAT\n#define CANCONCAT 0\n#endif\n\n");
         }
      }
      else
      {
         WRITE( "And text##text does work! GREAT!\n");
         fprintf( fp, "#ifndef CANCONCAT\n#define CANCONCAT 1\n#endif\n\n");
      }
   }
#endif

      /* If this kills your compiler, that's because it thinks that  */
      /* casting a pointer doesn't make it an lvalue any more.       */
      /* [which from my point of view is WRONG, but maybe according  */
      /* to ANSI. &%$* ANSI as I might add.]                         */
#if ! PHILOSOPHICAL_PROBLEM
   {
      char  d[4];
      long  *c = (long *) d;

      *((char *) c)++ = 0;
      if( ((char *) c - 1) != (void *) d)
         WRITE( "Philosophical problem, Casting before ++ doesn't work\n");

      c = (long *) d;
      *(char *)c++ = 0;
      if( ((char *) c - sizeof( long)) != (char *) d)
         WRITE( "Casting before ++ works, where it shouldn't have\n");
   }
#endif

   {
#define BYTES  (sizeof( long) << 2)
      char  x[ BYTES];
      long  *p = (long *) x;
      int   i;

      for( i = 0; i < BYTES; x[i++] = 0xFF);
      *p = *p++ = *p++ = *p++ = 0;
      for( i = 0; i < BYTES; i++)
         if( x[i])
         {
            WRITE( "Compiler has it's own ideas where it should ++\n");
            fprintf( fp, "#ifndef LATEPLUSPLUS\n#define LATEPLUSPLUS 1\n#endif\n\n");
            WRITE( "Set LATEPLUSPLUS to 1\n");
            goto fooble;
         }
      fprintf( fp, "#ifndef LATEPLUSPLUS\n#define LATEPLUSPLUS 0\n#endif\n\n");

fooble:
      if( i == BYTES)
      {
         i = 1;
         if( p++, i--)
            WRITE( "Compiler does --,++ as expected\n");
         else
            WRITE( "Compiler does --,++ not quite as\
 expected (but it doesn't matter for NASM)\n");
      }
   }

   {
      unsigned long     x = ~0;
      unsigned int      y = ~0;
      unsigned short    z = ~0;
      unsigned int      i, j, k, l;

      if( sizeof( size_t) == 2)
      {
         fprintf( stderr, "AHH!! PC detected. **BARF,RETCH**\n");
         fprintf( fp, "#define FUCKING_STOOPID_KLUDGE_SHIT 1\n\n");
      }
      for( i = 0; x; x >>= 1, i++);
      fprintf( stderr, "Unsigned longs have apparently %d bits\n", i);
      for( j = 0; y; y >>= 1, j++);
      fprintf( stderr, "Unsigned ints  have apparently %d bits\n", j);
      for( k = 0; z; z >>= 1, k++);
      fprintf( stderr, "Unsigned shorts have apparently %d bits\n", k);
      y = (byte) -1;
      for( l = 0; y; y >>= 1, l++);
      fprintf( stderr, "Unsigned chars have apparently %d bits\n", l);
      if( k == 16)
         fprintf( fp, "#define _WORD short\n");
      else
         if( j == 16)
            fprintf( fp, "#define _WORD int\n");
         else
            WRITE( "ERROR: No 16bit data type in sight (use bitfields??)\n");

      if( j == 32)
         fprintf( fp, "#define _LONG  int\n");
      else
         if( i == 32)
            fprintf( fp, "#define _LONG long\n");
         else
            WRITE( "ERROR: No 32bit data type in sight (use bitfields??)\n");

      if( l == 8)
         fprintf( fp, "#define _BYTE char\n");
      else
         if( k == 8)
            fprintf( fp, "#define _BYTE long\n");
         else
            WRITE( "ERROR: No 8bit data type in sight (use bitfields??)\n");
   }

   WRITE( "If you got ERRORs above, or if the data types aren't set correctly\
 yet\nthen diagnostics may be incorrect\n\n");

#ifdef __NSTDC__
# if __NSTDC__
   WRITE( "ANSI Compiler. ALL RIGHT!!\n");
# else
   WRITE( "ANSI Compiler ? Then why isn't __STDC__ 1 ?\n");
# endif
#endif
   i = 0x1234;
   p = (byte *) &i;
   if( *p == 0x12 && p[1] == 0x34)
   {
      WRITE( "Computer is LITTLE-ENDIAN (Lilliput)\n");
      fprintf( fp, "\n#ifndef LITTLEENDIAN\n#define LITTLEENDIAN 1\n#endif\n\n");
   }
   else
      if( *p == 0x34 && p[1] == 0x12)
      {
         WRITE( "Computer is BIG-ENDIAN (Blefuscu)\n");
         fprintf( fp, "\n#ifndef BIGENDIAN\n#define BIGENDIAN 1\n#endif\n\n");
      }
      else
      {
         WRITE( "Computer is weird (Brobdignang (sp?))\n");
         fprintf( stderr, "I expected $12 $34 or $34 $12 but got\
 $%02X $%02X\n",
                    (word) *p, (word) p[1]);
      }
   i = -10000;
   x = i;
   if( *p != *q || p[1] != q[1])
   {
      WRITE( "Conversion takes place between int and unsigned\n");
      x = (word) i;
      if( *p != *q || p[1] != q[1])
         WRITE( "Which can be suppressed with casting\n");
   }
#if SIGNAL
   if( (sdf = (int (*)()) signal( SIGADR, dofoo)) == (int (*)()) SIG_ERR)
   {
      WRITE( "Signal could not be set\n");
      goto over;
   }
   else
   {
      slword  i;
      sword   *p = (sword *) ((char *) &i + 1);
      register sword  x = (sword) 0x1234;

      *p = x;  /* TOS TURBO-C crashes here, cause they do signalling wrong */
   }           /* therefore we call continue from dofoo                    */
#endif
   xcontinue( 0);
#if SIGNAL
over:
   xcontinue( 1);
#endif
}

/* » Did the little cross (ASCII==187) produce an error ? Can your compiler
     only grok 7bit ASCII ?  NO PROBLEM. You can filter out any ASCII
     character over 127 w/o compromising source integrity.

     --- never tested nor compiled ---

     #include <stdio.h>
     main( argc, argv)
     char   *argv[];
     {
        register FILE   *fp, *fq;
        register int    c;

        fp = fopen( argv[1], "r");
        fq = fopen( argv[2], "w");

        while( (c = (int) getc( fp)) != EOF)
           if( (char) c >= 0)
              putc( c, fq);
     }

     ACKs & REFs

     Danny Cohen   ON HOLY WARS AND A PLEA FOR PEACE    (IEN 137 ??)
     Patrick Hayes COMPUTER ARCHITECTURE AND ORGANIZATION
 */

