/*
 * Random Numbers
 * For use with any ANSI C-Compiler
 * Tested with Maxon C/C++ 4.0
 */

#include <pragma/exec_lib.h>
#include <pragma/dos_lib.h>
#include <pragma/intuition_lib.h>

#include <clib/macros.h>

#include <stdlib.h>


struct Library *IntuitionBase = NULL;
LONG args[2] = {0, 0};
STRPTR tmplate = "HI=HIGH/K/N,LO=LOW/K/N\n";


LONG int2asc(char *c, LONG n, LONG b);

// retval = int2asc(targetstring, number to convert, numbers base);

// retval:          Numbers base for success, 0 if base not supported
// targetstring:    String with enough space to hold the ascii-ized number
// num. to convert: POSITIVE number only, if negative will be switched to positive !!!
// numbers base:    Base to which the number will be converted, currently only
//                  binary (2), octal (8) and decimal (10) support


void main(void)
{
   struct RDArgs *rdargs;
   ULONG secs, mics;
   LONG low = 0, high = 1, random, *num;
   int rw = RETURN_FAIL;
   char numbuf[8];

   IntuitionBase = OpenLibrary("intuition.library", 37);
   if(IntuitionBase)
   {
      rw = RETURN_ERROR;

      rdargs = ReadArgs(tmplate, args, NULL);
      if(rdargs)
      {
         rw = RETURN_OK;

         num = (LONG *) args[0];
         if(num)
         {
            high = *num;
         }

         num = (LONG *) args[1];
         if(num)
         {
            low = *num;
         }

         FreeArgs(rdargs);
      }

      CurrentTime(&secs, &mics); // Intuition interface to timer/GetSysTime

      secs %= (high + 1);        // Mask out anything above "high"
      random = MAX(secs, low);   // Make sure, value is at least "low"

      // No need to test the return value for base 10 here
      int2asc(numbuf, random, 10);

      // Create a dos shell variable named RANDOM
      if(SetVar("RANDOM", numbuf, -1, LV_VAR) == DOSFALSE)
      {
         rw = RETURN_ERROR;
      }

      CloseLibrary(IntuitionBase);
   }

   exit(rw);
}

// Here is the interesting part

LONG int2asc(char *c, LONG n, LONG b)
{
   char zahl[32]; // Widest range is binary: uses 32 chars, one for each bit
   LONG tmp, rw, i = 0;

   n = ABS(n);  // Get rid of a possibly signed value

   switch(b)
   {
      case 16:
         rw = 0;  // Not yet supported, but easy to implement. I don't need it here.
      break;

      case 10: // Anything equal to or below base 10 has the same handling
      case 8:
      case 2:
         // Generate ascii-ized string, is written REVERSED into the buffer !!!
         do
         {
            tmp = (n % b);
            tmp += 48;  // Promote the remainder to it's ascii equivalent
            zahl[i] = tmp;
            i++;
            n /= b;
         }
         while(n);

         c[i] = 0;      // Set the terminating null-byte
         i--;           // Adjust the counter
         while(i >= 0)  // Reverse copy the number to the string
         {
            *c = zahl[i];
            c++;
            i--;
         }

         rw = b;  // return "ok"
      break;

      default:
         rw = 0;  // return "not yet implemented"
      break;
   }

   return(rw);
}
