Example #1
1
void resman_check_watch(struct resman *rman)
{
    struct watch_dir *wdir;
    unsigned int idx;

    unsigned int num_handles = dynarr_size(rman->watch_handles);
    if(!num_handles) {
        return;
    }

    idx = WaitForMultipleObjectsEx(num_handles, rman->watch_handles, FALSE, 0, TRUE);
    if(idx == WAIT_FAILED) {
        unsigned int err = GetLastError();
        fprintf(stderr, "failed to check for file modification: %u\n", err);
        return;
    }
    if(idx >= WAIT_OBJECT_0 && idx < WAIT_OBJECT_0 + num_handles) {
        if(!(wdir = rb_find(rman->wdirbyev, rman->watch_handles[idx]))) {
            fprintf(stderr, "got change handle, but failed to find corresponding watch_dir!\n");
            return;
        }

        handle_event(rman, rman->watch_handles[idx], wdir);

        /* restart the watch call */
        ReadDirectoryChangesW(wdir->handle, wdir->buf, RES_BUF_SIZE, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE, 0, &wdir->over, 0);
    }
}
Example #2
0
int main(int argc, char **argv)
{
	int i;
	int *arr;

	if(argc < 2) {
		printf("pass a bunch of numbers to sort them\n");
		return 1;
	}

	/* create a new dynamic array of string pointers */
	arr = dynarr_alloc(0, sizeof *arr);

	for(i=1; i<argc; i++) {
		char *endp;
		int n = strtol(argv[i], &endp, 0);
		if(endp == argv[i]) {
			fprintf(stderr, "%s is not a number\n", argv[i]);
			dynarr_free(arr);
			return 1;
		}

		/* add a new string to the array (the argument is copied) */
		arr = dynarr_push(arr, &n);
	}

	qsort(arr, dynarr_size(arr), sizeof *arr, cmpfunc);

	for(i=0; i<dynarr_size(arr); i++) {
		printf("%d\n", arr[i]);
	}

	dynarr_free(arr);
	return 0;
}
Example #3
0
static struct dynarr *parse_specifier_qualifier_sc_internal(struct parser *parser, int mask) {
	union token tok;
	void *nd;
	struct dynarr *darr = dynarr_init();

	while (1) { 
		tok = lexer_next_token(parser->lexer);
		if ((mask & INTERNAL_PARSE_SPECIFIER) && initiate_type_specifier(tok)) {
			lexer_put_back(parser->lexer, tok);
			nd = parse_type_specifier(parser);
		} else if ((mask & INTERNAL_PARSE_QUALIFIER) && initiate_type_qualifier(tok)) {
			nd = type_qualifier_init(tok.tok_tag);
		} else if ((mask & INTERNAL_PARSE_STORAGE_CLASS) && initiate_storage_class_specifier(tok)) {
			nd = storage_class_specifier_init(tok.tok_tag);
		} else {
			lexer_put_back(parser->lexer, tok);
			break;
		}
		dynarr_add(darr, nd);
	}

#if DEBUG
	if (dynarr_size(darr) == 0) {
		// lexer_dump_remaining(parser->lexer); 
		file_reader_dump_remaining(parser->lexer->cstream);
		tok = lexer_next_token(parser->lexer); // this is putback
		token_dump(tok);
	}
#endif

	assert(dynarr_size(darr) > 0);
	return darr;
}
Example #4
0
void *resman_get_res_data(struct resman *rman, int res_id)
{
	if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
		return rman->res[res_id]->data;
	}
	return 0;
}
Example #5
0
char * lsystem_getRandProduction (const LSYSTEM * l, const char s) {
  PRODUCTION * sp = lsystem_getProduction (l, s);
  int i = 0;
  char
    * r = NULL,
    * v = NULL;
  //printf ("%s (%p, \'%c\')...\n", __FUNCTION__, l, s);
  if (sp == NULL) {
    r = xph_alloc_name (2, "LSYSTEM production");
    r[0] = s;
    r[1] = '\0';
    return r;
  }
  i = dynarr_size (sp->exp);
  if (i == 1) {
    v = *(char **)dynarr_front (sp->exp);
    //printf ("got \"%s\" as the 0-th index of %p\n", v, sp->exp);
    r = xph_alloc (strlen (v) + 1);
    strcpy (r, v);
    return r;
  }
  i = rand () % i;
  v = *(char **)dynarr_at (sp->exp, i);
  //printf ("got \"%s\" as the %d-th index of %p\n", v, i, sp->exp);
  r = xph_alloc (strlen (v) + 1);
  strcpy (r, v);
  //printf ("...%s\n", __FUNCTION__);
  return r;
}
Example #6
0
const char *resman_get_res_name(struct resman *rman, int res_id)
{
	if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
		return rman->res[res_id]->name;
	}
	return 0;
}
Example #7
0
void resman_destroy(struct resman *rman)
{
	int i;
	if(!rman) return;

	for(i=0; i<dynarr_size(rman->res); i++) {
		if(!rman->res[i]) continue;

		if(rman->destroy_func) {
			rman->destroy_func(i, rman->destroy_func_cls);
		}
		free(rman->res[i]->name);
		free(rman->res[i]);
	}
	dynarr_free(rman->res);

	resman_tpool_release(rman->tpool);

#if defined(WIN32) || defined(__WIN32__)
	dynarr_free(rman->wait_handles);
#else
	dynarr_free(rman->wait_fds);
#endif
	resman_destroy_file_monitor(rman);

	pthread_mutex_destroy(&rman->lock);
}
Example #8
0
// the caller should push and pop the typedef table
struct compound_statement *parse_compound_statement(struct parser *parser) {
	expect(parser->lexer, TOK_LBRACE);
	// lexer_push_typedef_tab(parser->lexer);

	// look one token ahead to determing if this is a declaration or statement or empty block
	union token tok = lexer_next_token(parser->lexer);
	struct dynarr *decl_or_stmt_list = dynarr_init();
	while (tok.tok_tag != TOK_RBRACE) {
		if (initiate_declaration(tok)) {
			#if 0	
			if (dynarr_size(stmtList) > 0) {
				panic("encounter declaration after statement");
			}
			#endif
			lexer_put_back(parser->lexer, tok);
			dynarr_add(decl_or_stmt_list, parse_declaration(parser));
		} else { // initiate a statement
			lexer_put_back(parser->lexer, tok);
			dynarr_add(decl_or_stmt_list, parse_statement(parser));
		}
		tok = lexer_next_token(parser->lexer);
	}
	// lexer_pop_typedef_tab(parser->lexer);
	return compound_statement_init(decl_or_stmt_list);
}
Example #9
0
static void pp_define_object_macro(struct lexer *lexer, const char *name) {
	struct dynarr *darr = store_token_until_newline(lexer);

	// simple check for: #define x x case.
	// a real example is in: /usr/include/bits/confname.h
	//
	// the ultimate way to sovle the (indirectly) referring itself obj/func macro is 
	// constructing the macro expanding tree
	if (dynarr_size(darr) == 1) {
		union token *tok = dynarr_get(darr, 0);
		if (tok->tok_tag == TOK_IDENTIFIER && strcmp(tok->id.s, name) == 0) {
			token_destroy(*tok);
			free(tok);
			dynarr_destroy(darr);
			red("ignore identity obj macro %s", name);
			return;
		}
	}
	struct macro *macro = obj_macro_init(darr);
	define_macro(lexer, name, macro);

#if DUMP_MACRO
	// fprintf(stderr, "%s define the macro %s\n", lexer->cstream->path, name);
	macro_dump(lexer, name, macro);
#endif
}
Example #10
0
int resman_get_res_result(struct resman *rman, int res_id)
{
	if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
		return rman->res[res_id]->result;
	}
	return -1;
}
Example #11
0
int resman_get_res_load_count(struct resman *rman, int res_id)
{
	if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
		return rman->res[res_id]->num_loads;
	}
	return -1;
}
Example #12
0
void resman_stop_watch(struct resman *rman, struct resource *res)
{
    int i, sz;
    struct watch_dir *wdir;

    if(!res->watch_path) {
        return;
    }

    if(!(wdir = rb_find(rman->watchdirs, res->watch_path))) {
        return;
    }

    /* if there is no other reference to this watch dir, destroy it */
    if(--wdir->nref <= 0) {
        /* find the handle in the watch_handles array and remove it */
        sz = dynarr_size(rman->watch_handles);
        for(i=0; i<sz; i++) {
            if(rman->watch_handles[i] == wdir->handle) {
                /* swap the end for it and pop */
                rman->watch_handles[i] = rman->watch_handles[sz - 1];
                rman->watch_handles[sz - 1] = 0;
                dynarr_pop(rman->watch_handles);
                break;
            }
        }

        rb_delete(rman->wdirbyev, wdir->over.hEvent);
        rb_delete(rman->watchdirs, wdir->watch_path);

        CancelIo(wdir->handle);
        CloseHandle(wdir->handle);
        CloseHandle(wdir->over.hEvent);
        free(wdir->watch_path);
        free(wdir);

        res->watch_path = 0;
    } else {
        /* just remove this watch item */
        if(wdir->items && wdir->items->res == res) {
            struct watch_item *tmp = wdir->items;
            wdir->items = wdir->items->next;
            free(tmp);
        } else {
            struct watch_item *wprev = wdir->items;
            struct watch_item *witem = wprev->next;

            while(witem) {
                if(witem->res == res) {
                    struct watch_item *tmp = witem;
                    wprev->next = witem->next;
                    break;
                }
                witem = witem->next;
            }
        }
    }
}
Example #13
0
static void wait_for_any_event(struct resman *rman)
{
	unsigned int num_handles;

	if(!(num_handles = dynarr_size(rman->wait_handles))) {
		return;
	}

	WaitForMultipleObjectsEx(num_handles, rman->wait_handles, FALSE, INFINITE, TRUE);
}
Example #14
0
// The declarator is for function
static void register_func_parameters_for_typedef(struct parser *parser, struct declarator *declarator) {
	struct dynarr *suff_list = declarator->direct_declarator->suff_list;
	assert(dynarr_size(suff_list) == 1);
	struct direct_declarator_suffix *suff = dynarr_get(suff_list, 0);
	assert(suff->empty_paren || suff->param_type_list != NULL);
	if (suff->param_type_list != NULL) {
		DYNARR_FOREACH_BEGIN(suff->param_type_list->param_decl_list, parameter_declaration, each);
			register_func_parameter_for_typedef(parser, each);
		DYNARR_FOREACH_END();
	}
}
Example #15
0
int lsystem_addProduction (LSYSTEM * l, const char s, const char * p) {
  PRODUCTION * sp = lsystem_getProduction (l, s);
  if (sp == NULL) {
    sp = production_create (s, p);
    dynarr_push (l->p, sp);
    dynarr_sort (l->p, production_sort);
  } else {
    production_addRule (sp, p);
  }
  return dynarr_size (sp->exp);
}
Example #16
0
static int find_resource(struct resman *rman, const char *fname)
{
	int i, sz = dynarr_size(rman->res);

	for(i=0; i<sz; i++) {
		if(strcmp(rman->res[i]->name, fname) == 0) {
			return i;
		}
	}
	return -1;
}
Example #17
0
static int add_resource(struct resman *rman, const char *fname, void *data)
{
	int i, idx = -1, size = dynarr_size(rman->res);
	struct resource *res;
	struct resource **tmparr;

	/* allocate a new resource */
	if(!(res = malloc(sizeof *res))) {
		return -1;
	}
	memset(res, 0, sizeof *res);

	res->name = strdup(fname);
	assert(res->name);
	res->data = data;
	pthread_mutex_init(&res->lock, 0);

	/* check to see if there's an empty (previously erased) slot */
	for(i=0; i<size; i++) {
		if(!rman->res[i]) {
			idx = i;
			break;
		}
	}

	if(idx == -1) {
		/* free slot not found, append a new one */
		idx = size;

		if(!(tmparr = dynarr_push(rman->res, &res))) {
			free(res->name);
			free(res);
			return -1;
		}
		rman->res = tmparr;
	} else {
		/* free slot found, just use it */
		res = rman->res[idx];
	}

	res->id = idx;	/* set the resource id */

	resman_reload(rman, rman->res[idx]);
	return idx;
}
Example #18
0
void nodedb_c_destruct(NodeCurve *n)
{
	unsigned int	i, num;

	num = dynarr_size(n->curves);
	for(i = 0; i < num; i++)
	{
		NdbCCurve	*c;

		if((c = dynarr_index(n->curves, i)) != NULL && c->name[0] != '\0')
		{
			printf("destroying curve %u\n", i);
			dynarr_destroy(c->keys);
			list_destroy(c->curve);
		}
	}
	dynarr_destroy(n->curves);
	n->curves = NULL;
}
Example #19
0
static void wait_for_any_event(struct resman *rman)
{
	int i, res, numfds, maxfd = 0;
	fd_set rdset;

	if(!(numfds = dynarr_size(rman->wait_fds))) {
		return;
	}

	FD_ZERO(&rdset);
	for(i=0; i<numfds; i++) {
		int fd = rman->wait_fds[i];
		FD_SET(fd, &rdset);
		if(fd > maxfd) maxfd = fd;
	}

	while((res = select(maxfd + 1, &rdset, 0, 0, 0)) == -1 && errno == EINTR);

	if(res == -1) {
		fprintf(stderr, "failed to wait for any events: %s\n", strerror(errno));
	}
}
Example #20
0
static void worldmap_input (EntComponent comp, EntSpeech speech)
{
	Entity
		this = component_entityAttached (comp);
	worldmapData
		map = component_getData (entity_getAs (Worldmap, "worldmap"));
	struct input_event
		* input = speech->arg;
	hexPos
		pos = position_get (entity_getByName ("PLAYER"));
	// the span index is backwards compared to usual because i'd like it to maintain the usual span mapping, which is 0 = hex level, MapSpan = pole level - xph 2012 01 17
	if (!input->active)
		return;

	switch (input->code)
	{
		case IR_UI_MENU_INDEX_DOWN:
			if (map->spanTypeFocus == FOCUS_SPAN && map->spanFocus != 0)
			{
				if (map->typeFocus != 0)
				{
					textureDestroy (map->spanTextures[map->spanFocus]);
					map->spanTextures[map->spanFocus] = NULL;
				}
				map->spanFocus--;
				map->types = mapDataTypes (hexPos_platter (pos, map->spanFocus));
				if (map->types)
					map->typeFocus = 0;
			}
			else if (map->types && map->typeFocus < (dynarr_size (map->types) - 1))
			{
				map->typeFocus++;
				if (map->spanTextures[map->spanFocus])
				{
					textureDestroy (map->spanTextures[map->spanFocus]);
					map->spanTextures[map->spanFocus] = NULL;
				}
			}
			break;
		case IR_UI_MENU_INDEX_UP:
			if (map->spanTypeFocus == FOCUS_SPAN && map->spanFocus != map->worldSpan)
			{
				if (map->typeFocus != 0)
				{
					textureDestroy (map->spanTextures[map->spanFocus]);
					map->spanTextures[map->spanFocus] = NULL;
				}
				map->spanFocus++;
				map->types = mapDataTypes (hexPos_platter (pos, map->spanFocus));
				if (map->types)
					map->typeFocus = 0;
			}
			else if (map->typeFocus != 0)
			{
				map->typeFocus--;
				if (map->spanTextures[map->spanFocus])
				{
					textureDestroy (map->spanTextures[map->spanFocus]);
					map->spanTextures[map->spanFocus] = NULL;
				}
			}
			break;
		case IR_UI_MODE_SWITCH:
			map->spanTypeFocus ^= 1;
			break;
		case IR_WORLDMAP_SWITCH:
			printf ("focusing world\n");
			entity_message (this, NULL, "loseFocus", NULL);
			entity_messageGroup ("PlayerAvatarEntities", NULL, "gainFocus", NULL);
			break;
		default:
			break;
	}
}
Example #21
0
int anm_get_animation_count(const struct anm_node *node)
{
    return dynarr_size(node->animations);
}
Example #22
0
int intstack_pop(struct intstack *stk) {
	assert(dynarr_size(stk) > 0);
	return (int) (long) stk->list[--stk->size];
}
Example #23
0
int intstack_subtop(struct intstack *stk) {
	assert(dynarr_size(stk) >= 2);
	return (int) (long) stk->list[stk->size - 2];
}
Example #24
0
		/* poll will be called with a high frequency anyway, so let's not spend
		 * too much time on done callbacks each time through it
		 */
		timeslice = rman->opt[RESMAN_OPT_TIMESLICE];
		if(timeslice > 0 && resman_get_time_msec() - start_time > timeslice) {
			break;
		}
	}
	return 0;
}

int resman_wait(struct resman *rman)
{
	wait_for_any_event(rman);
	return 0;
}

const char *resman_get_res_name(struct resman *rman, int res_id)
{
	if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
		return rman->res[res_id]->name;
	}
	return 0;
}

void resman_set_res_data(struct resman *rman, int res_id, void *data)
{
	if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
		rman->res[res_id]->data = data;
	}
}

void *resman_get_res_data(struct resman *rman, int res_id)
{
	if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
		return rman->res[res_id]->data;
	}
	return 0;
}

int resman_get_res_result(struct resman *rman, int res_id)
{
	if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
		return rman->res[res_id]->result;
	}
	return -1;
}

int resman_get_res_load_count(struct resman *rman, int res_id)
{
	if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
		return rman->res[res_id]->num_loads;
	}
	return -1;
}

#if defined(WIN32) || defined(__WIN32__)
int *resman_get_wait_fds(struct resman *rman, int *num_fds)
{
	static int once;
	if(!once) {
		once = 1;
		fprintf(stderr, "warning: resman_get_wait_fds does nothing on windows\n");
	}
	return 0;
}

void **resman_get_wait_handles(struct resman *rman, int *num_handles)
{
	*num_handles = dynarr_size(rman->wait_handles);
	return rman->wait_handles;
}

static void wait_for_any_event(struct resman *rman)
{
	unsigned int num_handles;

	if(!(num_handles = dynarr_size(rman->wait_handles))) {
		return;
	}

	WaitForMultipleObjectsEx(num_handles, rman->wait_handles, FALSE, INFINITE, TRUE);
}

#else /* UNIX */
int *resman_get_wait_fds(struct resman *rman, int *num_fds)
{
	*num_fds = dynarr_size(rman->wait_fds);
	return rman->wait_fds;
}
Example #25
0
int resman_poll(struct resman *rman)
{
	int i, num_res;
	unsigned long start_time, timeslice;

	/* first check all the resources to see if anyone is pending deletion */
	num_res = dynarr_size(rman->res);
	for(i=0; i<num_res; i++) {
		struct resource *res = rman->res[i];
		if(!res) {
			continue;
		}

		/* also make sure we're it's off the queues/workers before deleting */
		if(res->delete_pending && !res->pending) {
			if(rman->destroy_func) {
				rman->destroy_func(i, rman->destroy_func_cls);
			}
			remove_resource(rman, i);
		}
	}


	/* then check for modified files */
	resman_check_watch(rman);

#if !defined(WIN32) && !defined(__WIN32__)
	/* empty the thread pool event pipe (fd is nonblocking) */
	while(read(rman->tpool_wait_fd, &i, sizeof i) > 0);
#endif

	if(!rman->done_func) {
		return 0;	/* no done callback; there's no point in checking anything */
	}

	start_time = resman_get_time_msec();

	for(i=0; i<num_res; i++) {
		struct resource *res = rman->res[i];
		if(!res) {
			continue;
		}

		pthread_mutex_lock(&res->lock);
		if(!res->done_pending) {
			int reload = res->reload_timeout && res->reload_timeout <= start_time;
			pthread_mutex_unlock(&res->lock);
			if(reload) {
				printf("file \"%s\" modified, delayed reload\n", res->name);
				res->reload_timeout = 0;
				resman_reload(rman, res);
			}
			continue;
		}

		/* so a done callback *is* pending... */
		res->done_pending = 0;
		if(rman->done_func(i, rman->done_func_cls) == -1) {
			/* done-func returned -1, so let's remove the resource
			 * but only if this was the first load. Otherwise keep it
			 * around in case it gets valid again...
			 */
			if(res->num_loads == 0) {
				pthread_mutex_unlock(&res->lock);
				remove_resource(rman, i);
				continue;
			}
		}
		res->num_loads++;

		resman_start_watch(rman, res);	/* start watching the file for modifications */
		pthread_mutex_unlock(&res->lock);

		/* poll will be called with a high frequency anyway, so let's not spend
		 * too much time on done callbacks each time through it
		 */
		timeslice = rman->opt[RESMAN_OPT_TIMESLICE];
		if(timeslice > 0 && resman_get_time_msec() - start_time > timeslice) {
			break;
		}
	}
	return 0;
}
Example #26
0
void resman_set_res_data(struct resman *rman, int res_id, void *data)
{
	if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
		rman->res[res_id]->data = data;
	}
}
Example #27
0
void plugin_set_input(Plugin *p, int index, PValueType type, const char *name, va_list taglist)
{
	if(p == NULL)
		return;
	if(index < 0)
	{
		LOG_ERR(("Plug-in \"%s\" attempted to set input with negative index--ignored", p->name));
		return;
	}
	if((p->input == NULL && index != 0) || (p->input != NULL && (size_t) index != dynarr_size(p->input)))
	{
		LOG_ERR(("Plug-in \"%s\" attempted to set input \"%s\" with bad index %d--ignored", p->name, name, index));
		return;
	}
	if(type < P_VALUE_BOOLEAN || type > P_VALUE_MODULE)
	{
		LOG_ERR(("Plug-in \"%s\" attempted to set input %d with bad type %d--ignored", p->name, index, type));
		return;
	}
	if(p->input == NULL)
		p->input = dynarr_new(sizeof (Input), 2);
	if(p->input != NULL)
	{
		Input	i;

		stu_strncpy(i.name, sizeof i.name, name);
		i.type = type;
		i.spec.req = i.spec.def = i.spec.min = i.spec.max = 0;
		i.spec.enums = NULL;
		i.desc = NULL;
		value_init(&i.spec.min_val);
		value_init(&i.spec.max_val);
		value_init(&i.spec.def_val);
		
		for(;;)
		{
			int	tag = va_arg(taglist, int);
	
			if(tag == P_INPUT_TAG_DONE)
				break;
			else if(tag < P_INPUT_TAG_DONE || tag > P_INPUT_TAG_DESC)	/* Generous. */
			{
				LOG_WARN(("Aborting on bad tag value for %s.%s: %d", p->name, i.name, tag));
				break;
			}
			else if(tag == P_INPUT_TAG_REQUIRED)
				i.spec.req = 1;
			else if(tag == P_INPUT_TAG_MIN)
				i.spec.min = value_set_defminmax_va(&i.spec.min_val, i.type, &taglist);
			else if(tag == P_INPUT_TAG_MAX)
				i.spec.max = value_set_defminmax_va(&i.spec.max_val, i.type, &taglist);
			else if(tag == P_INPUT_TAG_DEFAULT)
				i.spec.def = value_set_defminmax_va(&i.spec.def_val, i.type, &taglist);
			else if(tag == P_INPUT_TAG_ENUM)
			{
				const char	*st;

				if(i.spec.enums == NULL)
					i.spec.enums = dynstr_new_sized(64);
				st = dynstr_string(i.spec.enums);
				if(st != NULL && *st != '\0' && st[strlen(st) - 1] != '|')	/* Make sure there are separators. */
					dynstr_append_c(i.spec.enums, '|');
				dynstr_append(i.spec.enums, va_arg(taglist, char *));
			}
			else if(tag == P_INPUT_TAG_DESC)
				i.desc = va_arg(taglist, char *);
		}
Example #28
0
static int sync_geometry_layer(const NodeGeometry *node, const NdbGLayer *layer,
				const NodeGeometry *target, const NdbGLayer *tlayer)
{
	const uint8	*data, *tdata;
	size_t		i, size, tsize, esize;
	int		send = 0;

/*	printf("synchronizing geometry layer '%s' against '%s'\n", layer->name, tlayer->name);*/

	/* Basically break the dynarr abstraction, for speed. */
	esize = dynarr_get_elem_size(layer->data);
	size  = dynarr_size(layer->data);
	tsize = dynarr_size(tlayer->data);
	data  = dynarr_index(layer->data, 0);
	tdata = dynarr_index(tlayer->data, 0);
/*	printf(" local geometry size: %u at %p, remote is %u at %p\n", size, data, tsize, tdata);*/
	for(i = 0; i < size; i++)
	{
		if(i >= tsize)					/* If data is not even in target, we must send it. */
			send = 1;
		else
		{
			send = memcmp(data, tdata, esize) != 0;	/* If it fits, compare to see if send needed. */
			/* If vertex layer, do more intelligent comparison for deleted vertices. */
			if(tlayer->id == 0 && tlayer->type == VN_G_LAYER_VERTEX_XYZ && tdata != NULL)
			{
				if(vertex_deleted((real64 *) data))
				{
					if(vertex_deleted((real64 *) tdata))
						send = 0;
				}
			}
			else if(tlayer->id == 1 && tlayer->type == VN_G_LAYER_POLYGON_CORNER_UINT32 && tdata != NULL)	/* And for polygon layers, too. */
			{
/*				printf("base polygon %u: local delete is %d, remote is %d, send=%d (local=%p remote=%p)\n",
				       i, polygon_deleted((uint32 *) data), polygon_deleted((uint32 *) tdata), send, data, tdata);
*/				if(polygon_deleted((uint32 *) data) && !polygon_deleted((uint32 *) tdata))
				{
/*					printf("  deleting polygon %u.%u\n", target->node.id, i);*/
					verse_send_g_polygon_delete(target->node.id, i);
					send = 0;
				}
			}
		}
/*		if(send)
			printf(" send %s %u in %u is %d\n", layer->name, i, node->node.id, send);
*/		if(send)
		{
			switch(tlayer->type)
			{
			case VN_G_LAYER_VERTEX_XYZ:
				verse_send_g_vertex_set_xyz_real64(target->node.id, tlayer->id, i,
							      ((const real64 *) data)[0],
							      ((const real64 *) data)[1], 
							      ((const real64 *) data)[2]);
				break;
			case VN_G_LAYER_VERTEX_UINT32:
				verse_send_g_vertex_set_uint32(target->node.id, tlayer->id, i, ((const uint32 *) data)[0]);
				break;
			case VN_G_LAYER_VERTEX_REAL:
				verse_send_g_vertex_set_real64(target->node.id, tlayer->id, i, ((const real64 *) data)[0]);
				break;
			case VN_G_LAYER_POLYGON_CORNER_UINT32:
				verse_send_g_polygon_set_corner_uint32(target->node.id, tlayer->id, i,
								       ((const uint32 *) data)[0],
								       ((const uint32 *) data)[1],
								       ((const uint32 *) data)[2],
								       ((const uint32 *) data)[3]);
				break;
			case VN_G_LAYER_POLYGON_CORNER_REAL:
				verse_send_g_polygon_set_corner_real64(target->node.id, tlayer->id, i,
								       ((const real64 *) data)[0],
								       ((const real64 *) data)[1],
								       ((const real64 *) data)[2],
								       ((const real64 *) data)[3]);
				break;
			case VN_G_LAYER_POLYGON_FACE_UINT8:
				verse_send_g_polygon_set_face_uint8(target->node.id, tlayer->id, i,
								       ((const uint8 *) data)[0]);
				break;
			case VN_G_LAYER_POLYGON_FACE_UINT32:
				verse_send_g_polygon_set_face_uint32(target->node.id, tlayer->id, i,
								       ((const uint32 *) data)[0]);
				break;
			case VN_G_LAYER_POLYGON_FACE_REAL:
				verse_send_g_polygon_set_face_real64(target->node.id, tlayer->id, i,
								       ((const real64 *) data)[0]);
				break;
			default:
				;
			}
		}
		data  += esize;
		tdata += esize;
	}
	if(size < tsize)	/* We have less data than the target, so delete remainder. */
	{
		send = 1;
		printf("** Target is too large, deleting -------------------------------------------------------\n");
/*		if(layer->type >= VN_G_LAYER_VERTEX_XYZ && layer->type < VN_G_LAYER_POLYGON_CORNER_UINT32)
		{
			for(i = size; i < tsize; i++)
				verse_send_g_vertex_delete_real64(target->node.id, i);
		}
*/		if(tlayer->id == 1)
		{
			printf("deleting excess polygons\n");
			for(i = size; i < tsize; i++)
				verse_send_g_polygon_delete(target->node.id, i);
		}
	}
	return send;
}