/*
 * libsal/syslimit/syslimit_iterate.c
 * Iterate through the supported system limits
 */

/*
 * Author(s)
 * Stuart Herbert (S.Herbert@sheffield.ac.uk)
 * Academic Computing Services
 * University of Sheffield
 */

#include <libsal/license.h>
#include <libsal/syslimit/internal.h>
#include <libsal/proto.h>
#include <libsal/defines.h>

/*
 * !! FUNCTION:	sal_syslimit_iterate
 * !! PURPOSE:	call this routine to iterate through the supported
 * !! PURPOSE:	limits list.  Set stLimitArg->iName to
 * !! PURPOSE:	be SAL_LIMIT_START in order to return the first
 * !! PURPOSE:	supported limit in the table.
 * 
 * !! A_NAME:	stLimitArg
 * !! A_TYPE:	sal_syslimit_entry *
 * !! A_DESC:	Pointer to the structure which will be filled with
 * !! A_DESC:	a copy of the next limit's entry in the syslimits table.
 * !! A_DESC:	This structure is not altered if you attempt to iterate
 * !! A_DESC:	beyond the end of the table.
 * 
 * !! R_TYPE:	int
 * !! R_DESC:	Returns TRUE (1) if a new supported limit has been found,
 * !! R_DESC:	or FALSE (0) if there are no more supported limits in the
 * !! R_DESC:	syslimits table.
 * 
 * !! END_FUNCTION:
 */

int sal_syslimit_iterate (sal_syslimit *stLimitArg)
{
  const sal_syslimit_entry *pstWalker = sal_syslimit_gettable();

  /*
   * if this assertion fails, we have been passed garbage
   */
  
  TEST_ARG(stLimitArg != NULL, 1);
  
  /*
   * if this assertion fails, then sal_syslimit_gettable()
   * has failed to pass us the correct pointer
   */
  
  ENSURE_DATA(pstWalker != NULL, "Internal system limits table corrupt!");
  
  /*
   * next, we make assertions about the known range of the available
   * limits.
   */
  
  TEST_ARG (stLimitArg->stLimitInfo.iName >= SAL_LIMIT_START, 1);
  TEST_ARG (stLimitArg->stLimitInfo.iName <= SAL_LIMIT_END,   1);

  /*
   * special case - if we're already at the end of the table, drop out
   */
  
  if (stLimitArg->stLimitInfo.iName == SAL_LIMIT_END)
    return 0;
  
  /*
   * find the user's current place in the table.  SAL_LIMIT_START is
   * a special case, which means that we want to iterate for the
   * very first time.
   */

  if (stLimitArg->stLimitInfo.iName > SAL_LIMIT_START)
    while (((pstWalker != NULL) && (pstWalker->iName != SAL_LIMIT_END)) &&
	   ((pstWalker->iName != stLimitArg->stLimitInfo.iName) ||
	    (pstWalker->iInterface != stLimitArg->stLimitInfo.iInterface)))
    {
      pstWalker++;
    }

  if (pstWalker == NULL)
    return 0;
  
  /* iterate to the next entry in the list */
  pstWalker++;
  
  /* find the next supported limit in the table */
  
  while ((pstWalker != NULL) && (pstWalker->iName != SAL_LIMIT_END) && (!sal_syslimit_supportedentry(pstWalker)))
  {
    pstWalker++;
  }
  
  if (pstWalker == NULL)
    return 0;
  else if (pstWalker->szName != NULL)
  {
    stLimitArg->stLimitInfo = *pstWalker;
    return 1;
  }
  else
  {
    return 0;
  }
}

