#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>

typedef unsigned char uint8;
typedef unsigned short uint16;
#if UINT_MAX >= 0xFFFFFFFF
typedef unsigned uint32;
#else
typedef unsigned long uint32;
#endif
typedef unsigned uint;

void MulInPlace(uint8* dst/* n bytes */,
                const uint8* src/* n bytes */,
                uint n)
{
  uint c1, c2;

  if (n >= 0xFFFF) abort();

  for (c1 = n - 1; c1 != ~0u; c1--)
  {
    uint16 s = 0;
    uint32 p = 0; // p must be able to store ceil(log2(n))+2*8 bits

    for (c2 = c1; c2 != ~0u; c2--)
    {
      p += dst[c2] * src[c1 - c2];
    }

    dst[c1] = (uint8)(p & 0xFF);

    for (c2 = c1 + 1; c2 < n; c2++)
    {
      p >>= 8;
      s += dst[c2] + (uint8)(p & 0xFF);
      dst[c2] = (uint8)(s & 0xFF);
      s >>= 8;
    }
  }
}

int ByteDivInPlace(uint8* dst/* n bytes */,
                   uint   n,
                   uint8  divisor,
                   uint8* remainder)
{
  uint rem = 0;
  int nonzero = 0;

  while (n)
  {
    rem += dst[n - 1];
    nonzero |= (dst[n - 1] = rem / divisor);
    rem = (rem % divisor) << 8;
    n--;
  }

  if (remainder != NULL)
    *remainder = (uint8)(rem >> 8);

  return nonzero; // 1 if the quotient is non-zero, 0 otherwise
}

void IncInPlace(uint8* dst/* n bytes */,
                uint n)
{
  uint c = 1;
  while (n-- && c)
  {
    c += *dst;
    *dst++ = c & 0xFF;
    c >>= 8;
  }
}

void DestroyingDecimalPrint(uint8* dst, uint n)
{
  uint8 r;
  if (ByteDivInPlace(dst, n, 10, &r))
    DestroyingDecimalPrint(dst, n);
  printf("%d", r);
}

int main(void)
{
  int i;
  uint8 factorial[66];
  uint8 factor[sizeof(factorial)];
  uint8 tmp[sizeof(factorial)];

  // factor = 1
  memset(factor, 0, sizeof(factor));
  factor[0] = 1;

  // factorial = 1
  memcpy(factorial, factor, sizeof(factorial));

  for (i = 1; i <= 100; i++)
  {
    // factorial *= factor
    MulInPlace(factorial, factor, sizeof(factorial));

    // tmp = factorial
    memcpy(tmp, factorial, sizeof(factorial));

    // print i and tmp
    printf("%i! = ", i);
    DestroyingDecimalPrint(tmp, sizeof(tmp));
    printf("\n");

    // factor += 1
    IncInPlace(factor, sizeof(factor));
  }

  return 0;
}
