Exemple #1
0
MEMTRN *
mem_new_trans_(
    const char *filename,               /*  Name of source file making call  */
    word lineno                         /*  Line number in calling source    */
)
{
    MEMTRN
       *trn;                            /*  Allocated transaction block      */

    /*  Allocate block                                                       */
    trn = malloc (MEMTRN_SIZE);
    if (trn == NULL)
        return (NULL);

#   if (defined (MEM_TRACE))
    if (filename)
        trace ("%s (%d): new transaction", filename, lineno);
#   endif

    trn-> file = (char *) filename;     /*  Who allocated it                 */
    trn-> line = lineno;                /*    and where                      */
    list_reset (&trn-> memhdr);         /*  No memory blocks yet             */

    list_reset (trn);                   /*  Only 1 item in list              */
    list_relink_before (trn, &tr_list);  /*  Add to list of transactions      */
    return (trn);                       /*   and return address              */
}
Exemple #2
0
bool list_seek(struct list_cursor *cur, int index) {
	assert(cur);
	assert(cur->list);

	if (index < 0) {
		if ((unsigned) abs(index) > cur->list->length) return false;
		list_reset(cur);
		cur->target = cur->list->tail;
		while (cur->target && cur->target->dead) {
			cur->target = cur->target->prev;
		}
		list_item_ref(cur->target);
		while (++index) {
			bool ok = list_prev(cur);
			assert(ok);
		}
	} else {
		if ((unsigned) index >= cur->list->length) return false;
		list_reset(cur);
		cur->target = cur->list->head;
		while (cur->target && cur->target->dead) {
			cur->target = cur->target->next;
		}
		list_item_ref(cur->target);
		while (index--) {
			bool ok = list_next(cur);
			assert(ok);
		}
	}
	return true;
}
Exemple #3
0
/*
====================================================================
Load all levelSETS listed in 'levelsets' (names) into one big
levelset and shake the levels a bit. Use a fixed seed for this
and reinit random generator with current time when done.
Use sets from install directory only (no preceding ~)
====================================================================
*/
LevelSet *levelset_load_all( List *levelsets, int seed, int addBonusLevels )
{
	LevelSet *set;
	char *setname;
	int version, update;
	List *levels = list_create( LIST_NO_AUTO_DELETE, 0 );
	int i, j, num;
	ListEntry *entry;
	Level **pointers, *level;

        /* use sets from install directory only (no preceding ~) */
	list_reset( levelsets );
	while ( (setname = list_next( levelsets )) && setname[0] != '~' )
        levels_load( setname, levels, &version, &update );
	
    /* shake the levels a bit */
    srand(seed);
    list_reset( levels ); i = 0;
    pointers = calloc( levels->count, sizeof( Level* ) );
    while ( ( level = list_next( levels ) ) ) {
        i = rand() % levels->count;
        while ( pointers[i] ) {
            i++;
            if ( i == levels->count )
                i = 0;
        }
        pointers[i] = level;
    }
    entry = levels->head->next;
    for ( i = 0; i < levels->count; i++ ) {
        entry->item = pointers[i];
        entry = entry->next;
    }
    free( pointers );
    /* add bonus levels every four normal levels */
    if (addBonusLevels)
    {
        srand(addBonusLevels);
        num = levels->count / 4;
        for (i=0,j=4;i<num;i++)
        {
            level = level_create_empty("Michael Speck", "Bonus Level");
            level->type = RANDOM(LT_JUMPING_JACK,LT_LAST-1);
            list_insert(levels,level,j);
            j += 5;
        }
    }
    srand(time(0));
        
	version = 1; update = 0;
	set = levelset_build_from_list( levels, TOURNAMENT, version, update );
	if ( set == 0 )
		fprintf( stderr, "empty levelset: %s\n", TOURNAMENT );
	else
		printf( "%s v%i.%02i: %i levels\n", TOURNAMENT, 
			set->version, set->update, set->count );
	return set;
}
Exemple #4
0
void ai_eval_hexes( int x, int y, int range, int(*eval_func)(int,int,void*), void *ctx )
{
    List *list = list_create( LIST_NO_AUTO_DELETE, LIST_NO_CALLBACK );
    AI_Pos *pos;
    int i, nx, ny;
    /* gather and handle all positions by breitensuche.
       use AUX mask to mark visited positions */
    map_clear_mask( F_AUX );
    list_add( list, ai_create_pos( x, y ) ); mask[x][y].aux = 1;
    list_reset( list );
    while ( list->count > 0 ) {
        pos = list_dequeue( list );
        if ( !eval_func( pos->x, pos->y, ctx ) ) {
            free( pos );
            break;
        }
        for ( i = 0; i < 6; i++ )
            if ( get_close_hex_pos( pos->x, pos->y, i, &nx, &ny ) )
                if ( !mask[nx][ny].aux && get_dist( x, y, nx, ny ) <= range ) {
                    list_add( list, ai_create_pos( nx, ny ) );
                    mask[nx][ny].aux = 1;
                }
        free( pos );
    }
    list_delete( list );
}
Exemple #5
0
void list_cursor_destroy(struct list_cursor *cur) {
	assert(cur);
	assert(cur->list);
	list_reset(cur);
	list_unref(cur->list);
	free(cur);
}
Exemple #6
0
/*
====================================================================
Functions to access a PData tree. 
'name' is the pass within tree 'pd' where subtrees are separated 
by '/' (e.g.: name = 'config/graphics/animations')
parser_get_pdata   : get pdata entry associated with 'name'
parser_get_entries : get list of subtrees (PData structs) in 'name'
parser_get_values  : get value list of 'name'
parser_get_value   : get a single value from value list of 'name'
parser_get_int     : get first value of 'name' converted to integer
parser_get_double  : get first value of 'name' converted to double
parser_get_string  : get first value of 'name' _duplicated_
If an error occurs result is set NULL, False is returned and
parse_error is set.
====================================================================
*/
int parser_get_pdata  ( PData *pd, const char *name, PData  **result )
{
    int i, found;
    PData *pd_next = pd;
    PData *entry = 0;
    char *sub = 0;
    List *path = parser_explode_string( name, '/' );
    for ( i = 0, list_reset( path ); i < path->count; i++ ) {
        ListIterator it;
        sub = list_next( path );
        if ( !pd_next->entries ) {
            sprintf( parser_sub_error, tr("%s: no subtrees"), pd_next->name );
            goto failure;
        }
        it = list_iterator( pd_next->entries ); found = 0;
        while ( ( entry = list_iterator_next( &it ) ) )
            if ( strlen( entry->name ) == strlen( sub ) && !strncmp( entry->name, sub, strlen( sub ) ) ) {
                pd_next = entry;
                found = 1;
                break;
            }
        if ( !found ) {
            sprintf( parser_sub_error, tr("%s: subtree '%s' not found"), pd_next->name, sub );
            goto failure;
        }
    }
    list_delete( path );
    *result = pd_next;
    return 1;
failure:
    sprintf( parser_error, "parser_get_pdata: %s/%s: %s", pd->name, name, parser_sub_error );
    list_delete( path );
    *result = 0;
    return 0;
}
Exemple #7
0
/*
====================================================================
Save chart in directory it was loaded from.
====================================================================
*/
void chart_save()
{
    char file_name[512];
    int i;
	Set_Chart *chart = 0;
    FILE *file = 0;
    if ( !chart_loaded ) return;
    /* full file name */
    sprintf( file_name, "%s/%s", chart_path, CHART_FILE_NAME );

    if (!strcmp(chart_path, HI_DIR) && hi_dir_chart_file) {
        file = hi_dir_chart_file;
        rewind(hi_dir_chart_file);
    }
    else {
        /* open file */
        file = fopen( file_name, "w" );
    }

    if ( !file ) {
        fprintf( stderr, _("??? Highscore chart loaded properly but cannot save? (%s)\n"),file_name );
        return;
    }
	/* save all charts */
	list_reset( charts );
	while ( ( chart = list_next( charts ) ) !=  0 ) {
		fprintf( file, ">>>%s\n", chart->name );
    	for ( i = 0; i < CHART_ENTRY_COUNT; i++ )
        	fprintf( file, "%s\n%i\n%i\n", chart->entries[i].name, chart->entries[i].level, chart->entries[i].score );
	}		

    if (file != hi_dir_chart_file)
        fclose( file );
}
Exemple #8
0
void *
mem_realloc_ (
    void       *client_ptr,             /*  Block of memory to reallocate    */
    size_t      size,                   /*  Desired size of memory block     */
    const char *filename,               /*  Name of source file making call  */
    word        lineno                  /*  Line number in calling source    */
)
{
    MEMHDR
        *ptr,
        *next;

    ASSERT (client_ptr);
    ASSERT (size > 0);

    /*  Check that block is valid                                            */
    ptr = CLIENT_2_HDR (client_ptr);
    if (ptr-> tag != MEMTAG)
        mem_tag_err (ptr, filename, lineno);

    /*  Invalidate header                                                    */
    ptr-> tag = MEMUNTAG;

    mem_total -= ptr-> size;
    mem_free_count += 1;

    
    next = ptr-> next;                  /*  Save where we were linked        */
    list_unlink (ptr);                  /*     and unlink                    */
    
    /*  Reallocate memory block                                              */
    ptr = (MEMHDR *) realloc (ptr, RESERVE_SIZE + size);
    if (ptr == NULL)                    /*  If nothing free, do a hunt       */
      {                                 /*    and try again...               */
        mem_scavenge ();
        ptr = (MEMHDR *) realloc (ptr, RESERVE_SIZE + size);
        if (ptr == NULL)
            return (NULL);              /*  Really in trouble now!           */
      }

#   if (defined (MEM_TRACE))
    if (filename)
        trace ("%s (%d): realloc %d bytes ->%p", filename, lineno, size, ptr);
#   endif

    /*  Update header                                                        */
    ptr-> tag  = MEMTAG;
    ptr-> size = size;
    ptr-> file = filename;
    ptr-> line = lineno;

    list_reset (ptr);                   /*  Set up block as list             */
    list_relink_before (ptr, next);     /*  And link where old block was     */

    mem_total += size;                  /*  Keep count of space used         */
    mem_alloc_count += 1;               /*    and number of allocations      */

    return (HDR_2_CLIENT (ptr));
}
ClientUser* client_find_user( int id )
{
    ClientUser *entry;
    list_reset( client_users );
    while ( ( entry = list_next( client_users ) ) )
        if ( entry->id == id )
            return entry;
    return 0;
}
Exemple #10
0
/** Resets the list to contain a copy of the items in the given
    array. The capacity of the list will match the length of the
    provided array.

    @param l The list to be modified.
    
    @param numItems The number of items in the array that is to be
    copied into the list. Also, this will be the initial capacity of
    the list.

    @param itemSize The size of each item in the array (and in the
    list that is going to be set up).

    @param array An array containing items to be copied into the list.

    @return 1 if success, 0 if failure.
 */
int list_reset_import(list *l, int numItems, int itemSize, int (*compar)(const void *, const void *), void *array)
{
	/* reset the list so it has exactly the capacity needed */
	if(list_reset(l, numItems, itemSize, compar) == 0)
		return 0;

	memcpy(l->data, array, itemSize * numItems);
	l->length = numItems;
	l->compar = compar;
	return 1;
}
Exemple #11
0
/*
====================================================================
Clear all new_entry flags (done before new players are added
to chart when game over).
====================================================================
*/
void chart_clear_new_entries()
{
    int i;
    Set_Chart *chart;
    list_reset( charts );
    while ( ( chart = list_next( charts ) ) != 0 ) {
        chart->entries[CHART_ENTRY_COUNT].score = chart->entries[CHART_ENTRY_COUNT].level = 0;
        for ( i = 0; i < CHART_ENTRY_COUNT + 1; i++ ) 
            chart->entries[i].new_entry = 0;
    }
}
Exemple #12
0
int list_shrink( list_t *list_in, int mdec_in )
{
	void *tmp;
	list_reset( list_in ); /* Force list_in->start to coincide with list_in->pointer */
	tmp = realloc( list_in->pointer, ( list_in->alloc - mdec_in ) * list_in->step );
	if( tmp == NULL )
		return -1;
	list_in->pointer = tmp;
	list_in->start = list_in->pointer;
	list_in->alloc -= mdec_in;
	return list_in->alloc;
}
Exemple #13
0
MODULE initialise_the_thread (THREAD *thread)
{
    tcb = thread-> tcb;                 /*  Point to thread's context        */
    if (tcb-> thread_type == master_event)
      {
        tcb-> ip_value  = NULL;
        tcb-> host_name = NULL;
        list_reset (&tcb-> stack);      /*  Initialise requests stack        */
        list_reset (&tcb-> reply);      /*  Initialise reply list            */
        cache_table = sym_create_table ();
      }
    tcb-> query          = NULL;
    tcb-> handle         = 0;
    tcb-> readsize       = 0;
    tcb-> current_ns_ip  = 0;
    tcb-> cur_request    = NULL;
    tcb-> invalid_ns_tab = NULL;
    tcb-> rr_result      = NULL;
    tcb-> rr_result_nbr  = 0;
    tcb-> send_responce  = FALSE;
}
Exemple #14
0
/*
====================================================================
Set key value if VALUE_KEY and clear grab flag
====================================================================
*/
void value_set_key( Value *value, int val_int )
{
    Value *other_key;
    if ( !value->filter[val_int] ) return;
    list_reset( value->other_keys );
    while ( ( other_key = list_next( value->other_keys ) ) )
        if ( *other_key->val_int == val_int ) return;
    /* ok, set */
    *value->val_int = val_int;
    value->grab = 0;
    value_update_str( value );
}
Exemple #15
0
int list_grow( list_t *list_in, int minc_in )
{
	void *tmp;
	list_reset( list_in );
	tmp = realloc( list_in->pointer, ( list_in->alloc + minc_in ) * list_in->step );
	if( tmp == NULL )
		return -1;
	list_in->pointer = tmp;
	list_in->start = list_in->pointer;
	list_in->alloc += minc_in;
	return list_in->alloc;
}
Exemple #16
0
/** Creates a new list with enough capacity to store 'capacity' items
    which are each itemSize bytes.
    
    @param capacity Number of items that we should allocate space in
    the list for.

    @param itemSize The size of each item to be stored in the list.

    @return A pointer to a list struct or NULL if we failed to
    allocate the list. The list should eventually be free'd with
    list_free().
*/
list* list_new(int capacity, int itemSize, int (*compar)(const void *, const void *))
{
	list *l = malloc(sizeof(list));
	if(l == NULL)
	{
		msg(ERROR, "Failed to allocate space for a list which can hold %d %d byte items.", capacity, itemSize);
		return NULL;
	}
	l->data = NULL;
	if(list_reset(l, capacity, itemSize, compar) == 0)
		return NULL;
	return l;
}
Exemple #17
0
/*! \brief  Loops over all cache entries and checks each one of them.
 */
static bool
check_cache_content (list *cache)
{
  bool pass = true;
  _model_info_t *info;

  list_reset (cache);
  while ((info = list_next (cache)))
    {
      pass &= check_info_content (info);
    }
  return pass;
}
Exemple #18
0
XML_ITEM *
xml_create (
    const char *name,
    const char *value)
{
    XML_ITEM
        *item;

    list_create (item, sizeof (XML_ITEM));
    if (item)
      {
        list_reset (&item-> attrs);
        list_reset (&item-> children);
        item-> parent = NULL;
        item-> name   = mem_strdup (name);
        item-> value  = mem_strdup (value);

        return (item);
      }
    else
        return (NULL);
}
Exemple #19
0
/*
====================================================================
Query set chart by this name or if not found create a new one
by this name.
====================================================================
*/
Set_Chart* chart_set_query( char *name )
{
	Set_Chart *chart = 0;
	list_reset( charts );
	while ( ( chart = list_next( charts ) ) != 0 )
		if ( strequal( name, chart->name ) )
			return chart;
	/* not found so create it */
	fprintf( stderr, _("First chart query for '%s'. Creating this chart.\n"), name );
	chart = chart_set_create( name );
	list_add( charts, chart );
	return chart;
}
Exemple #20
0
/* change theme */
void cb_change_theme()
{
    Menu *menu;
    theme_load( theme_names[config.theme_id] );
    hint_set_bkgnd( mbkgnd );
    /* apply the new background to all items */
    list_reset( menus );
    while ( ( menu = list_next( menus ) ) ) {
        menu_set_bkgnd( menu, mbkgnd );
        menu_set_fonts( menu, mcfont, mfont, mhfont );
    }
    stk_surface_blit( mbkgnd, 0,0,-1,-1, stk_display, 0,0 );
    stk_display_update( STK_UPDATE_ALL );
}
Exemple #21
0
/*
====================================================================
This function frees a PData tree struct.
====================================================================
*/
void parser_free( PData **pdata )
{
    PData *entry = 0;
    if ( (*pdata) == 0 ) return;
    if ( (*pdata)->entries ) {
        list_reset( (*pdata)->entries );
        while ( ( entry = list_next( (*pdata)->entries ) ) )
            parser_free( &entry );
        list_delete( (*pdata)->entries );
    }
    if ( (*pdata)->name ) free( (*pdata)->name );
    if ( (*pdata)->values ) list_delete( (*pdata)->values );
    common_tree_data_deref((*pdata)->ctd);
    free( *pdata ); *pdata = 0;
}
Exemple #22
0
void *
list_attach (LIST *list, void *data, size_t size)
{
    LIST
        *node;

    node = mem_alloc (sizeof (LIST) + size);
    if (node)
      {
        list_reset (node);
        list_relink_after (node, list);
        memcpy ((char *) node + sizeof (LIST), (char *) data, size);
      }
    return node;
}
Exemple #23
0
local
add_user_data  (TCB *tcb, LIST *head)
{
    USER_DATA
        *user;

    user = mem_alloc (sizeof (USER_DATA));
    if (user)
      {
        user-> reply_to = tcb-> reply_to;
        user-> tag      = tcb-> user_tag;
        list_reset (user);
        list_relink_after (user, head);
      }
}
Exemple #24
0
MODULE create_request_thread (THREAD *thread)
{
    THREAD
        *child;                         /*  Handle to child thread           */
    TCB
        *main_tcb;
    char
        *thread_name = NULL;

    main_tcb = thread-> tcb;

    if (main_tcb-> main_req_type == REQ_TYPE_HOST)
        thread_name = main_tcb-> ip_value;
    else
        thread_name = main_tcb-> host_name;
    if (thread_name == NULL)
        thread_name = "";
    if ((child = thread_create (AGENT_NAME, thread_name)) != NULL)
      {
        event_send (
            &child-> queue-> qid,       /*  Send to child thread queue       */
            &thread-> event-> sender,   /*  Queue for reply                  */
            "_CLIENT",                  /*  Name of event to send            */
            thread-> event-> body,      /*  Event body                       */
            thread-> event-> body_size, /*    and size                       */
            NULL, NULL, NULL,           /*  No response events               */
            0);                         /*  No timeout                       */
        tcb = (TCB *) child-> tcb;

        list_reset (&tcb-> reply);
        add_user_data (main_tcb, &tcb-> reply);
        tcb-> thread_type   = client_event;
        tcb-> main_req_type = main_tcb-> main_req_type;
        tcb-> host_name     = NULL;
        tcb-> ip_value      = NULL;
        if (tcb-> main_req_type == REQ_TYPE_HOST)
          {
            tcb-> ip_address = main_tcb-> ip_address;
            tcb-> ip_value   = mem_strdup (main_tcb-> ip_value);
            mem_strfree (&main_tcb-> ip_value);
          }
        else
          {
            tcb-> host_name = mem_strdup (main_tcb-> host_name);
            mem_strfree (&main_tcb-> host_name);
          }
      }
}
Exemple #25
0
void *
list_unlink (
    void *list)
{
    list_unsafe = TRUE;

    /*  Join together next and previous nodes */
    ((LIST *) ((LIST *) list)-> prev)-> next = ((LIST *) list)-> next;
    ((LIST *) ((LIST *) list)-> next)-> prev = ((LIST *) list)-> prev;

    /*  The list is now empty */
    list_reset ((LIST *) list);

    list_unsafe = FALSE;
    return (list);
}
Exemple #26
0
void *
mem_alloc_ (
    MEMTRN     *trn,                    /*  Associated transaction           */
    size_t      size,                   /*  Desired size of memory block     */
    const char *filename,               /*  Name of source file making call  */
    word        lineno                  /*  Line number in calling source    */
)
{
    MEMHDR
       *ptr;                            /*  Allocated memory block           */

    /*  Allocate block with extra space for the header                       */
    ASSERT (size > 0);                  /*  Cannot allocate zero bytes!      */

    ptr = malloc (RESERVE_SIZE + size);
    if (ptr == NULL)                    /*  If nothing free, do a hunt       */
      {                                 /*    and try again...               */
        mem_scavenge ();
        ptr = malloc (RESERVE_SIZE + size);
        if (ptr == NULL)
            return (NULL);              /*  Really in trouble now!           */
      }
#   if (defined (MEM_TRACE))
    if (filename)
        trace ("%s (%d): alloc %d bytes->%p", filename, lineno, size, ptr);
#   endif

    ptr-> tag  = MEMTAG;                /*  Initialise block header          */
    ptr-> size = size;                  /*  Size of block                    */
    ptr-> file = filename;              /*  Who allocated it                 */
    ptr-> line = lineno;                /*    and where                      */

    if (!trn)                           /*  If no transaction then use the   */
        trn = &mem_list;                /*  main block list                  */

    list_reset (ptr);                   /*  Set up new block as list         */
    list_relink_before (ptr,            /*  Add to list of blocks            */
                        &trn-> memhdr);

    mem_total += size;                  /*  Keep count of space used         */
    mem_alloc_count += 1;               /*    and number of allocations      */

    return (HDR_2_CLIENT (ptr));        /*   and return client address       */
}
Exemple #27
0
MODULE prepare_client_thread (THREAD *thread)
{
    int
       index;
    NS_REQUEST
       *new_req,
       *request;

    tcb = thread-> tcb;                 /*  Point to thread's context        */

    if (server_list.ns_count == 0)
        raise_exception (initialisation_error_event);

    /* Create first request on the stack with DNS configuration              */
    list_reset (&tcb-> stack);
    request = rdns_request_alloc (tcb-> ip_address, tcb-> ip_value,
                                  tcb-> host_name,
                                  tcb-> main_req_type);
    if (request)
      {
        request-> ns_ip   = server_list.ns_addr [0].sin_addr.s_addr;
        request-> ns_port = server_list.ns_addr [0].sin_port;
        request-> main_request = TRUE;
        request-> main_index   = 0;
        request-> recursive    = server_list.recursive_accept [0];
        list_relink_after (request, &tcb-> stack);
        for (index = 1; index < server_list.ns_count; index++)
          {
            new_req = rdns_request_alloc (tcb-> ip_address, tcb-> ip_value,
                                          tcb-> host_name,
                                          tcb-> main_req_type);
            new_req-> ns_ip   = server_list.ns_addr [index].sin_addr.s_addr;
            new_req-> ns_port = server_list.ns_addr [index].sin_port;
            new_req-> main_request = TRUE;
            new_req-> main_index   = (byte)index;
            new_req-> recursive    = server_list.recursive_accept [index];
            list_relink_after (new_req, request);
            request = new_req;
          }
      }
    tcb-> cur_request = tcb-> stack.next;
    tcb-> invalid_ns_tab = sym_create_table ();
}
Exemple #28
0
MODULE initialise_the_program (void)
{
    /*  Reset returned list                                                  */
    feedback = mem_alloc (sizeof (LIST));
    list_reset (feedback);

    /*  Token is at most the same length as the string                       */
    token   = mem_alloc (strlen (string) + 1);
    scanptr = string;

    /*  By default, numbers are handled as US/UK decimals                    */
    if (decimal == ',')
        comma = '.';
    else {
        decimal = '.';
        comma   = ',';
    }
    the_next_event = ok_event;
}
Exemple #29
0
int
list_insert(list *l, dtype d)
{
    node *p = l->head;
    node *n = (node *) malloc(sizeof(node));
    if (n == NULL) return -1;
    bzero(n, sizeof(node));    
    n->data = d;
    n->next = NULL;
    if (l->head == NULL) {
	l->head = n;
	return 1;
    } else {
	while (p->next != NULL) {
	    p = p->next;
	}
	p->next = n;
    }
    list_reset(l);
    return 1;
}
Exemple #30
0
/*
====================================================================
Build a levelset from a level list and delete the list.
The levels are taken from the list so it must not have AUTO_DELETE
enabled!
====================================================================
*/
LevelSet *levelset_build_from_list( List *levels, char *name, int version, int update )
{
	LevelSet *set = 0;
	Level *level;
	int i = 0;
	
	if ( levels->count == 0 ) return 0;
	set = salloc( 1, sizeof( LevelSet ) );
	snprintf( set->name, 20, "%s", name );
	set->levels = salloc( levels->count, sizeof( Level* ) );
	set->count = levels->count;
	set->version = version;
	set->update = update;
	list_reset( levels );
	while ( (level = list_next( levels )) ) {
		set->levels[i] = level;
		i++;
	}
	list_delete( levels );
	return set;
}