/*
 * nqs_generic/all-systems/secgrfir.c
 * Compare two resource limits.
 */

#include <nqs_generic/license.h>
  /* NQS license information */
#include <nqs_generic/debug.h>
  /* debugging support */
#include <nqs_generic/proto.h>
  /* ANSI C prototype support */
#include <nqs_queue/quolim.h>
  /* for struct quotalimit and quota limit units */

/*** secgrfir
 *
 *	int secgrfir():
 *
 *	Given two quota limits, return 1 if the second limit
 *	is greater than the first limit. Otherwise return 0.
 *
 *	This function was originally designed to return 1 whenever
 *	the units were unequal. Then I considered the example
 *	1.2 GB, 1 GB.  The fractional part algorithm converts
 *	the UNITS of the first to MEGABYTES! Once the 12 comparisons
 *	to handle this were in, it seemed natural to add the remaining
 *	44.  This in turn allowed grandfather clauses and other benefits.
 *
 *	It is assumed that the number of bits in an unsigned
 *	long is at least 32.  It is further assumed that first_quota
 *	and second_quota are each < 2**32.
 */
int secgrfir (
	unsigned long first_quota,
	short first_units,
	unsigned long second_quota,
	short second_units)
{
  ENTER_FUNCTION("nqs_generic/all-systems/secgrfir");
    /* debugging information */
  
  if (first_units == 0 || second_units == 0)
  {
    EXIT_FUNCTION;
    return (1);
  }
  /*
   * Below, we handle the 8 pairs where the units are identical.
   */
  if (first_units == second_units)
  {
    EXIT_FUNCTION;
    return (second_quota > first_quota);
  }
  /*
   * Below, we handle the 56 remaining possible pairs of units.
   * Where the first units are coarser than the second units,
   * we have to add 1023, 1048575, 1073741823, BYTES_PER_WORD -1,
   * (BYTES_PER_WORD * 1024) -1, (BYTES_PER_WORD * 10485476) -1,
   * or (BYTES_PER_WORD * 1073741824) -1 to handle the case
   * "1 kb 1025 b", which would otherwise appear legal.
   */
  switch (first_units)
  {
   case QLM_BYTES:
    switch (second_units)
    {
     case QLM_WORDS:
      EXIT_FUNCTION;
      return (first_quota / BYTES_PER_WORD < second_quota);
     case QLM_KBYTES:
      EXIT_FUNCTION;
      return (first_quota / 1024 < second_quota);
     case QLM_KWORDS:
      EXIT_FUNCTION;
      return ((first_quota / 1024) / BYTES_PER_WORD < second_quota);
     case QLM_MBYTES:
      EXIT_FUNCTION;
      return (first_quota / 1048576L < second_quota);
     case QLM_MWORDS:
      EXIT_FUNCTION;
      return ((first_quota / 1048576L) / BYTES_PER_WORD < second_quota);
     case QLM_GBYTES:
      EXIT_FUNCTION;
      return (first_quota / 1073741824UL < second_quota);
     case QLM_GWORDS:
      EXIT_FUNCTION;
      return ((first_quota / 1073741824UL) / BYTES_PER_WORD < second_quota);
    }
   case QLM_WORDS:
    switch (second_units)
    {
     case QLM_BYTES:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - (BYTES_PER_WORD - 1))
      {
	EXIT_FUNCTION;
	return (first_quota <= second_quota / BYTES_PER_WORD);
      }
      EXIT_FUNCTION;
      return (first_quota < (second_quota + (BYTES_PER_WORD - 1)) / BYTES_PER_WORD);
     case QLM_KBYTES:
      if ((first_quota / 1024) * BYTES_PER_WORD >= second_quota)
      {
	EXIT_FUNCTION;
	return (0);
      }
      if ((first_quota / 1024 == second_quota / BYTES_PER_WORD) &&
	  ((first_quota % 1024) * BYTES_PER_WORD >=
	  (second_quota % BYTES_PER_WORD) * 1024))
      {
	EXIT_FUNCTION;
	return (0);
      }
      EXIT_FUNCTION;
      return (1);
     case QLM_KWORDS:
      EXIT_FUNCTION;
      return (first_quota / 1024 < second_quota);
     case QLM_MBYTES:
      if ((first_quota / 1048576L) * BYTES_PER_WORD >= second_quota)
      {
	EXIT_FUNCTION;
	return (0);
      }
      if ((first_quota / 1048576L == second_quota / BYTES_PER_WORD) &&
	  ((first_quota % 1048576L) * BYTES_PER_WORD >=
	   (second_quota % BYTES_PER_WORD) * 1048576L))
      {
	EXIT_FUNCTION;
	return (0);
      }
      EXIT_FUNCTION;
      return (1);
     case QLM_MWORDS:
      EXIT_FUNCTION;
      return (first_quota / 1048576L < second_quota);
     case QLM_GBYTES:
      if ((first_quota / 1073741824UL) * BYTES_PER_WORD >= second_quota)
      {
	EXIT_FUNCTION;
	return (0);
      }
      /*
       * In the test below, we give up a factor of 8 in accuracy
       * to ensure that the multiplication does not overflow.
       */
      if ((first_quota / 1073741824UL == second_quota / BYTES_PER_WORD) &&
	  (((first_quota % 1073741824UL) / 8) * BYTES_PER_WORD >=
	   (second_quota % BYTES_PER_WORD) * (1073741824UL / 8)
	  )
	 )
      {
	EXIT_FUNCTION;
	return (0);
      }
      EXIT_FUNCTION;
      return (1);
     case QLM_GWORDS:
      EXIT_FUNCTION;
      return (first_quota / 1073741824UL < second_quota);
    }
    
   case QLM_KBYTES:
    switch (second_units)
    {
     case QLM_BYTES:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - 1023)
      {
	EXIT_FUNCTION;
	return (first_quota < 4194304L);
      }
      else
      {
	EXIT_FUNCTION;
	return (first_quota < (second_quota + 1023)/1024);
      }
     case QLM_WORDS:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - (1024 - 1))
      {
	EXIT_FUNCTION;
	return ( first_quota < (4194304L * BYTES_PER_WORD));
      }
      if (first_quota / BYTES_PER_WORD >= (second_quota + (1024 - 1)) / 1024)
      {
	EXIT_FUNCTION;
	return (0);
      }
      if ((first_quota / BYTES_PER_WORD == second_quota / 1024) &&
	  ((first_quota % BYTES_PER_WORD) * 1024 >= (second_quota % 1024) * BYTES_PER_WORD))
      {
	EXIT_FUNCTION;
	return (0);
      }
      EXIT_FUNCTION;
      return (1);
     case QLM_KWORDS:
      EXIT_FUNCTION;
      return (first_quota / BYTES_PER_WORD < second_quota);
     case QLM_MBYTES:
      EXIT_FUNCTION;
      return (first_quota / 1024 < second_quota);
     case QLM_MWORDS:
      EXIT_FUNCTION;
      return ((first_quota / 1024) / BYTES_PER_WORD < second_quota);
     case QLM_GBYTES:
      EXIT_FUNCTION;
      return (first_quota / 1048576L < second_quota);
     case QLM_GWORDS:
      EXIT_FUNCTION;
      return ((first_quota / 1048576L) / BYTES_PER_WORD < second_quota);
    }
   case QLM_KWORDS:
    switch (second_units)
    {
     case QLM_BYTES:
       /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - ((BYTES_PER_WORD * 1024) -1))
      {
	EXIT_FUNCTION;
	return (first_quota <= second_quota / (BYTES_PER_WORD * 1024));
      }
      return (first_quota < (second_quota + ((BYTES_PER_WORD * 1024) -1)) / (BYTES_PER_WORD * 1024));
     case QLM_WORDS:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - 1023)
      {
	EXIT_FUNCTION;
	return (first_quota < 4194304L);
      }
      else
      {
	EXIT_FUNCTION;
	return (first_quota < (second_quota + 1023)/1024);
      }
     case QLM_KBYTES:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - (BYTES_PER_WORD -1))
      {
	EXIT_FUNCTION;
	return (first_quota <= second_quota / BYTES_PER_WORD);
      }
      EXIT_FUNCTION;
      return (first_quota < (second_quota + (BYTES_PER_WORD - 1)) / BYTES_PER_WORD);
     case QLM_MBYTES:
      if ((first_quota / 1024) * BYTES_PER_WORD >= second_quota)
      {
	EXIT_FUNCTION;
	return (0);
      }
      if ((first_quota / 1024 == second_quota / BYTES_PER_WORD) &&
	  ((first_quota % 1024) * BYTES_PER_WORD >= (second_quota % BYTES_PER_WORD) * 1024))
      {
	EXIT_FUNCTION;
	return (0);
      }
      EXIT_FUNCTION;
      return (1);
     case QLM_MWORDS:
      EXIT_FUNCTION;
      return (first_quota / 1024 < second_quota);
     case QLM_GBYTES:
      if ((first_quota / 1048576L) * BYTES_PER_WORD >= second_quota)
      {
	EXIT_FUNCTION;
	return (0);
      }
      if ((first_quota / 1048576L == second_quota / BYTES_PER_WORD) &&
	  ((first_quota % 1048576L) * BYTES_PER_WORD >=	(second_quota % BYTES_PER_WORD) * 1048576L))
      {
	EXIT_FUNCTION;
	return (0);
      }
      EXIT_FUNCTION;
      return (1);
     case QLM_GWORDS:
      EXIT_FUNCTION;
      return (first_quota / 1048576L < second_quota);
    }
   case QLM_MBYTES:
    switch (second_units)
    {
     case QLM_BYTES:
       /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - 1048575L)
      {
	EXIT_FUNCTION;
	return (first_quota < 4096);
      }
      else
      {
	EXIT_FUNCTION;
	return (first_quota < (second_quota + 1048575L)/1048576L);
      }
     case QLM_WORDS:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - (1048576L - 1))
      {
	EXIT_FUNCTION;
	return ( first_quota < (4096L * BYTES_PER_WORD));
      }
      if (first_quota / BYTES_PER_WORD >= (second_quota + (1048576L - 1)) / 1048576L)
      {
	EXIT_FUNCTION;
	return (0);
      }
      if ((first_quota / BYTES_PER_WORD == second_quota / 1048576L) &&
	  ((first_quota % BYTES_PER_WORD) * 1048576L >=	(second_quota % 1048576L) * BYTES_PER_WORD))
      {
	EXIT_FUNCTION;
	return (0);
      }
      EXIT_FUNCTION;
      return (1);
     case QLM_KBYTES:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - 1023)
      {
	EXIT_FUNCTION;
	return (first_quota < 4194304L);
      }
      else
      {
	EXIT_FUNCTION;
	return (first_quota < (second_quota + 1023)/1024);
      }
     case QLM_KWORDS:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - (1024 - 1))
      {
	EXIT_FUNCTION;
	return ( first_quota < (4194304L * BYTES_PER_WORD));
      }
      if (first_quota / BYTES_PER_WORD >= (second_quota + (1024 - 1)) / 1024)
      {
	EXIT_FUNCTION;
	return (0);
      }
      if ((first_quota / BYTES_PER_WORD == second_quota / 1024) &&
	  ((first_quota % BYTES_PER_WORD) * 1024 >= (second_quota % 1024) * BYTES_PER_WORD))
      {
	EXIT_FUNCTION;
	return (0);
      }
      EXIT_FUNCTION;
      return (1);
     case QLM_MWORDS:
      EXIT_FUNCTION;
      return (first_quota / BYTES_PER_WORD < second_quota);
     case QLM_GBYTES:
      EXIT_FUNCTION;
      return (first_quota / 1024 < second_quota);
     case QLM_GWORDS:
      EXIT_FUNCTION;
      return ((first_quota / 1024) / BYTES_PER_WORD < second_quota);
    }
   case QLM_MWORDS:
    switch (second_units)
    {
     case QLM_BYTES:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - ((BYTES_PER_WORD * 1048576L) -1))
      {
	EXIT_FUNCTION;
	return (first_quota <= second_quota / (1048576L * BYTES_PER_WORD));
      }
      EXIT_FUNCTION;
      return (first_quota < (second_quota + ((BYTES_PER_WORD * 1048576L) -1)) / (BYTES_PER_WORD * 1048576L));
     case QLM_WORDS:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - 1048575L)
      {
	EXIT_FUNCTION;
	return (first_quota < 4096);
      }
      else
      {
	EXIT_FUNCTION;
	return (first_quota < (second_quota + 1048575L)/1048576L);
      }
     case QLM_KBYTES:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - ((BYTES_PER_WORD * 1024) -1))
      {
	EXIT_FUNCTION;
	return (first_quota <= second_quota / (BYTES_PER_WORD * 1024));
      }
      EXIT_FUNCTION;
      return (first_quota < (second_quota + ((BYTES_PER_WORD * 1024) -1)) / (BYTES_PER_WORD * 1024));
     case QLM_KWORDS:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - 1023)
      {
	EXIT_FUNCTION;
	return (first_quota < 4194304L);
      }
      else
      {
	EXIT_FUNCTION;
	return (first_quota < (second_quota + 1023)/1024);
      }
      NEVER;
     case QLM_MBYTES:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - (BYTES_PER_WORD -1))
      {
	EXIT_FUNCTION;
	return (first_quota <= second_quota / BYTES_PER_WORD);
      }
      EXIT_FUNCTION;
      return (first_quota < (second_quota + (BYTES_PER_WORD - 1)) / BYTES_PER_WORD);
     case QLM_GBYTES:
      if ((first_quota / 1024) * BYTES_PER_WORD >= second_quota)
      {
	EXIT_FUNCTION;
	return (0);
      }
      if ((first_quota / 1024 == second_quota / BYTES_PER_WORD) &&
	  ((first_quota % 1024) * BYTES_PER_WORD >= (second_quota % BYTES_PER_WORD) * 1024))
      {
	EXIT_FUNCTION;
	return (0);
      }
      EXIT_FUNCTION;
      return (1);
     case QLM_GWORDS:
      EXIT_FUNCTION;
      return (first_quota / 1024 < second_quota);
    }
    NEVER;
   case QLM_GBYTES:
    switch (second_units)
    {
     case QLM_BYTES:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - 1073741823UL)
      {
	EXIT_FUNCTION;
	return (first_quota < 4);
      }
      else
      {
	EXIT_FUNCTION;
	return (first_quota < (second_quota + 1073741823UL)/1073741824UL);
      }
      NEVER;
     case QLM_WORDS:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - (1073741824UL - 1))
      {
	EXIT_FUNCTION;
	return ( first_quota < (4L * BYTES_PER_WORD));
      }
      if (first_quota / BYTES_PER_WORD >= (second_quota + (1073741824UL - 1)) / 1073741824UL)
      {
	EXIT_FUNCTION;
	return (0);
      }
      /*
       * In the test below, we give up a factor of 8 in accuracy
       * to ensure that the multiplication does not overflow.
       */
      if ((first_quota / BYTES_PER_WORD == second_quota / 1073741824UL) &&
	  ((first_quota % BYTES_PER_WORD) * (1073741824UL / 8)  >= ((second_quota % 1073741824UL) / 8) * BYTES_PER_WORD))
      {
	EXIT_FUNCTION;
	return (0);
      }
      EXIT_FUNCTION;
      return (1);
     case QLM_KBYTES:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - 1048575L)
      {
	EXIT_FUNCTION;
	return (first_quota < 4096);
      }
      else
      {
	EXIT_FUNCTION;
 	return (first_quota < (second_quota + 1048575L)/1048576L);
      }
     case QLM_KWORDS:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - (1048576L - 1))
      {
	EXIT_FUNCTION;
	return ( first_quota < (4096L * BYTES_PER_WORD));
      }
      if (first_quota / BYTES_PER_WORD >= (second_quota + (1048576L - 1)) / 1048576L)
      {
	EXIT_FUNCTION;
	return (0);
      }
      if ((first_quota / BYTES_PER_WORD == second_quota / 1048576L) &&
	  ((first_quota % BYTES_PER_WORD) * 1048576L >= (second_quota % 1048576L) * BYTES_PER_WORD))
      {
	EXIT_FUNCTION;
	return (0);
      }
      EXIT_FUNCTION;
      return (1);
     case QLM_MBYTES:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - 1023)
      {
	EXIT_FUNCTION;
	return (first_quota < 4194304L);
      }
      else
      {
	EXIT_FUNCTION;
	return (first_quota < (second_quota + 1023)/1024);
      }
     case QLM_MWORDS:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - (1024 - 1))
      {
	EXIT_FUNCTION;
	return ( first_quota < (4194304L * BYTES_PER_WORD));
      }
      if (first_quota / BYTES_PER_WORD >= (second_quota + (1024 - 1)) / 1024)
      {
	EXIT_FUNCTION;
	return (0);
      }
      if ((first_quota / BYTES_PER_WORD == second_quota / 1024) &&
	  ((first_quota % BYTES_PER_WORD) * 1024 >= (second_quota % 1024) * BYTES_PER_WORD))
      {
	EXIT_FUNCTION;
	return (0);
      }
      EXIT_FUNCTION;
      return (1);
     case QLM_GWORDS:
      EXIT_FUNCTION;
      return (first_quota / BYTES_PER_WORD < second_quota);
     default:
      NEVER;
    }
   case QLM_GWORDS:
    switch (second_units)
    {
     case QLM_BYTES:
      if (BYTES_PER_WORD >= 4)
      {
	/*
	 * Recall that second_quota is < 2**32.
	 */
	EXIT_FUNCTION;
	return (first_quota == 0 && second_quota > 0);
      }
      else
      {
	/* Before adding, check for overflow. */
	if (second_quota > 4294967295UL - ((BYTES_PER_WORD * 1073741824UL) -1))
	{
	  EXIT_FUNCTION;
	  return (first_quota <= second_quota / (1073741824UL * BYTES_PER_WORD));
	}
	EXIT_FUNCTION;
	return (first_quota < (second_quota + ((BYTES_PER_WORD * 1073741824UL) -1)) /
		(BYTES_PER_WORD * 1073741824UL));
      }
     case QLM_WORDS:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - 1073741823UL)
      {
	EXIT_FUNCTION;
	return (first_quota < 4);
      }
      else
      {
	EXIT_FUNCTION;
	return (first_quota < (second_quota + 1073741823UL)/1073741824UL);
      }
     case QLM_KBYTES:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - ((BYTES_PER_WORD * 1048576L) -1))
      {
	EXIT_FUNCTION;
	return (first_quota <= second_quota / (1048576L * BYTES_PER_WORD));
      }
      EXIT_FUNCTION;
      return (first_quota < (second_quota + ((BYTES_PER_WORD * 1048576L) -1)) /
	      (BYTES_PER_WORD * 1048576L));
     case QLM_KWORDS:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - 1048575L)
      {
	EXIT_FUNCTION;
	return (first_quota < 4096);
      }
      else
      {
	EXIT_FUNCTION;
	return (first_quota < (second_quota + 1048575L)/1048576L);
      }
      NEVER;
     case QLM_MBYTES:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - ((BYTES_PER_WORD * 1024) -1))
      {
	EXIT_FUNCTION;
	return (first_quota <= second_quota / (BYTES_PER_WORD * 1024));
      }
      EXIT_FUNCTION;
      return (first_quota < (second_quota + ((BYTES_PER_WORD * 1024) -1)) /
	      (BYTES_PER_WORD * 1024));
     case QLM_MWORDS:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - 1023)
      {
	EXIT_FUNCTION;
	return (first_quota < 4194304L);
      }
      else
      {
	EXIT_FUNCTION;
	return (first_quota < (second_quota + 1023)/1024);
      }
     case QLM_GBYTES:
      /* Before adding, check for overflow. */
      if (second_quota > 4294967295UL - (BYTES_PER_WORD -1))
      {
	EXIT_FUNCTION;
	return (first_quota <= second_quota / BYTES_PER_WORD);
      }
      EXIT_FUNCTION;
      return (first_quota < (second_quota + (BYTES_PER_WORD - 1)) / BYTES_PER_WORD);
    }
  }
  NEVER;
  return 0;
}				/* end secgrfir () */
