// endian.cc  P. Conrad   CISC181 Fall 2005
// Three utility functions for determining "endian-ness"

// You can use 
//  #include "endian.h"
// to define the function prototypes for these functions 

#include <iostream>
using std::cerr;
using std::endl;

bool systemIsLittleEndian()
{
  int x=65;
  int * addressOfX = &x;  // addressOfX is the location of x in memory

  // int * is a type that means "a pointer to an integer".
  // an int * can be used as any of the following:
  //     (a) a pointer to an integer
  //     (b) the address of an integer
  //     (c) the name of an array of integers [more on that later]
  
  char c[4];


  // Note that the name of an array (e.g. c) refers to the address in 
  // memory where that array "lives".  So an array name like c
  // is also a (char *), or "pointer to character".  It can be considered
  //   (a) a pointer to a character (the element [0] in the array)
  //   (b) the address of a character (the element [0] in the array)
  //   (c) the name of an array of characters.

  // The memcpy() function will copy four bytes from where X lives 
  // into the array called c.   

  // (void *) means "generic pointer"; it converts a particular kind of
  // address (e.g. (int *) or (char *) into a "generic address".
  // C++ would normally complain about us "mixing types".   Type casting
  // (putting (void *) in front of an expression) signals the compiler
  // that we "know what we are doing" and are accepting the consequences.

  memcpy((void *) c, (void *) addressOfX, 4);  

  if ( c[0] == '\0' &&  c[1] == '\0' &&  c[2] == '\0' &&  c[3] == 'A')
    {
      return false;
    }
  else if ( c[0] == 'A' &&  c[1] == '\0' &&  c[2] == '\0' &&  c[3] == '\0')
    {
      return true;
    }
  else
    {
      cerr << "I can't tell is your system is big or little endian" << endl;
      cerr << "Something is probably wrong with the program." << endl;
      exit(1);
    }
}

int convertToLittleEndian(int x)
{
  if (systemIsLittleEndian())
    return x;

  char c[4];
  memcpy((void *) c, (void *) &x, 4);

  char temp = c[0];
  c[0] = c[3];
  c[3] = temp;

  temp = c[2];
  c[2] = c[1];
  c[1] = temp;

  memcpy((void *) &x, (void *) c, 4);

  return x;
      
}

signed short convertShortToLittleEndian(signed short x)
{
  if (systemIsLittleEndian())
    return x;

  char c[2];
  memcpy((void *) c, (void *) &x, 2);

  char temp = c[0];
  c[0] = c[1];
  c[1] = temp;

  memcpy((void *) &x, (void *) c, 2);

  return x;

}



