/*
   fichier machine/machine.c
   version 1 sept. 2007 par whygee@f-cpu.org

   Ce petit programme détecte les paramètres critiques
   du système sur lequel il tourne. Il génère le fichier
   machine.h qui est utilisé par def64.h et def32.h,
   mais il peut être modifié pour correspondre à
   d'autres architectures cibles.

   Note : les variables sont prévues pour supporter
   "au moins" le nombre de bits voulu, il faut que le
   programme cible s'accomode de tailles plus grandes.
 */

#include <stdio.h>

unsigned long long int i[2]={
/* évite un warning inutile */
#ifdef __GNUC__
0x3837363534333231LL,
#else
0x3837363534333231,
#endif
  0}; /* pour le zéro terminal */
  
int main(int argc, char *argv[]) {
  char *c=(char *)&i,
    *endian="#error UNDEFINED ENDIAN",
    *u32="#error UNDEFINED U32";
  int j;
  int ssi, si, sli;

  /* shift wraparound : */
  int k;
  long long int l;
  char *wrap32, *wrap64;

  if (sizeof(char)!=1) {
    printf("#error sizeof(char) = %i != 1\n",
       (int)sizeof(char));
  }

  if (sizeof(short int) < 2) {
    printf("#error sizeof(short int) = %i < 2\n",
       (int)sizeof(short int));
  }

  ssi = sizeof(short int);
   si = sizeof(int);
  sli = sizeof(long int);

  if (sizeof(int)>=4) {
    u32="int";
  } 
  else {
    if (sizeof(long int)>=4) {
      u32="long int";
    }
    else {
      printf("#error incapable de trouver le nom d'un type 32 bits\n");
      printf("#error sizeof(int) = %i, sizeof(long int) = %i\n",
       (int)sizeof(int), (int)sizeof(long int));
    }
  }

  if (sizeof(long long int)!=8) {
    printf("#error sizeof(long long int) = %i != 8 */\n",
       (int)sizeof(long long int));
  } 

  if ((c[0]=='8') && (c[1]=='7') && (c[2]=='6') && (c[3]=='5')
   && (c[4]=='4') && (c[5]=='3') && (c[6]=='2') && (c[7]=='1')
   && (c[8]==0)) {
    endian="#define WORDS_BIGENDIAN";
  }
  else {
    if ((c[0]=='1') && (c[1]=='2') && (c[2]=='3') && (c[3]=='4')
     && (c[4]=='5') && (c[5]=='6') && (c[6]=='7') && (c[7]=='8')
     && (c[8]==0)) {
      endian="/* Little Endian détecté, #undef WORDS_BIGENDIAN */";
    }
    else {
      printf("#error Endian=%s ???\n",c);
    }
  }

  printf("\
/* fichier machine.h\n\
 Attention ! ce fichier a été généré par machine.c\n\
date:\n\
uname\n\
*/\n\
\n\
#ifndef __MACHINE_H__\n\
#define __MACHINE_H__\n\
\n\
/* sizeof(short int)=%d\n\
   sizeof(      int)=%d\n\
   sizeof(long  int)=%d */\n\
", ssi, si, sli);

  printf("\n\
#define U8    unsigned char\n\
#define S8      signed char\n\
\n\
#define U16   unsigned short int\n\
#define S16     signed short int\n\
\n\
#define U32   unsigned %s\n\
#define S32     signed %s\n\
\n\
#define U64   unsigned long long int\n\
#define S64     signed long long int\n\
\n\
/* Endian : */\n\
#define ENDIAN64 %s\n\
%s\n\
\n\
", u32, u32, c, endian);

/* test des paramètres d'entrée
 pour les opérations de décalage.
 Ce n'est pas encore très fiable :-/ */

  k=0;
  for (j=0; j<33; j++)
    k ^= 1<<j;

  if (k==-2)
    wrap32="#define SHIFT_WRAP32";
  else
    wrap32="/* #undef SHIFT_WRAP32 */";

  l=0;
  for (j=0; j<65; j++)
    l ^=
#ifdef __GNUC__
1LL
#else
1
#endif
<<j;

  if (l==-2)
    wrap64="#define SHIFT_WRAP64";
  else
    wrap64="/* #undef SHIFT_WRAP64 */";

  printf("/* Shift wraparound :\n\
résultat 32 bits : %08X\n\
résultat 64 bits : %016llX */\n\
%s\n\
%s\n\
\n\
#endif\n\
", k, l, wrap32, wrap64);

  return 0;
}
