/* list.c */

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

#include "clibExtra.h"
#include "error.h"

#include "toolbox.h"

#include "find.h"
#include "list.h"

/* First call, enter with list.
   Subsequent calls enter with list = NULL.
   terminator is the character terminating the list, # when string building.
   object and component must be pointers.
   If processing a range then sets *separator to dividing character.
   Sets *separator to 0 for last item in range.
   Returns o = -1 and c = -1 to finish.
*/
  
_kernel_oserror *listItem
( char *list, char terminator,
  ObjectId *object, ComponentId *component, char *separator)
{ static ObjectId o;                   /* current object    */
  static ComponentId c;                /* current component */
  static ComponentId rangeLimit = -1;  /* last in range or -1 if not range */
  static char *buffer, *b;             /* copy of list, pointer into list */

  ObjectId ot;
  char *p, t, *colon;
  _kernel_oserror *er = NULL;

  if( !object || !component || !separator )
     error( "listItem() requires object, component and separator pointers" );
     
  /* check for first call ie start a new list */
  if( list )
  { free( buffer );
    buffer = myMalloc( strlen(list) + 1);
    /* remove all spaces from the list and copy */
    for( p = list, b = buffer; *p != terminator; p++ )
      if( *p != ' ' ) *b++ = *p;
    *b = 0;
    b = buffer;
    o = c = rangeLimit = -1;
  }

  /* check for range continuing */
  if( rangeLimit != -1 )
  { c++;
    if( c == rangeLimit ) *separator = 0;
    if( c > rangeLimit )
    { c = rangeLimit = -1;
      if( !b ) o = -1;

    }
    else
    { *object = o;
      *component = c;
      return NULL;
    }    
  }
  
  /* check for list finished */
  if( !b )
  { *object = *component = -1;
    return NULL;
  }

  /* range not continuing */
  if( rangeLimit == -1 && b )
  { p = strpbrk( b, ",-=" );        /* find next separator */
    if( !p ) for( p = b; *p; p++ ); /* or if none, end of string */
    t = *p;                         /* record the separator */
    *p++ = 0;                       /* replace with 0 */

    colon = strchr( b, ':' );
    if( colon )
    { if( b != colon ) /* there is an object name */
      { *colon = 0;
        ot = find_object( b );
        if( ot != -1 )
          o = ot;
        else
        { sprintf( error_block.errmess, "List object %s not found", b );
          error_block.errnum = 0;
          return &error_block;
        }
      }
      /* if a hex digit follows, then there is a component id */
      c = isxdigit( *++colon ) ? (ComponentId) strtol( colon, 0, 16 ) : -1;
    }
    else
    { /* no colon so see if it is an object */
      ot = find_object( b );
      if( ot != -1 )
      { o = ot;
        c = -1;
      }  
      else
        /* not an object, so it must be a component id */
        c = (ComponentId) strtol( b, NULL, 16 );
    }
    b = p;
    
    if( t == '-' || t == '=' )
    /* it is a range so the separator is followed by a component id */
    { if( c == -1 ) error( "Range has no starting component" ); /**generalise */
      *separator = t;
      if( *b == ':' ) b++; /* may have a leading ':' so skip it */
      rangeLimit = (ComponentId) strtol( b, &b, 16 );
      t = *b++;
    }

    if( t == 0 ) b = NULL;
  }  

  *object = o;
  *component = c;
  return er;
}
