示例#1
0
文件: alist.c 项目: jnbek/TekNap
Array_item *add_to_array (Array *array, Array_item *item)
{
	int count;
	int location = 0;
	Array_item *ret = (void *) 0 ;
	u_32int_t       mask;    

	if (array->hash == HASH_INSENSITIVE)
		item->hash = ci_alist_hash(item->name, &mask);
	else
		item->hash = cs_alist_hash(item->name, &mask);

	check_array_size(array);
	if (array->max)
	{
		find_array_item(array, item->name, &count, &location);
		if (count < 0)
		{
			ret = ((Array_item *) (( array ) -> list [ (  location ) ])) ;
			array->max--;
		}
		else
			move_array_items(array, location, array->max, 1);
	}

	array->list[location] = item;
	array->max++;
	return ret;
}
示例#2
0
/*
 * Returns an entry that has been displaced, if any.
 */
Array_item *BX_add_to_array (Array *array, Array_item *item)
{
	int count;
	int location = 0;
	Array_item *ret = NULL;
	u_32int_t       mask;   /* Dummy var */

	if (array->hash == HASH_INSENSITIVE)
		item->hash = ci_alist_hash(item->name, &mask);
	else
		item->hash = cs_alist_hash(item->name, &mask);

	check_array_size(array);
	if (array->max)
	{
		find_array_item(array, item->name, &count, &location);
		if (count < 0)
		{
			ret = ARRAY_ITEM(array, location);
			array->max--;
		}
		else
			move_array_items(array, location, array->max, 1);
	}

	array->list[location] = item;
	array->max++;
	return ret;
}
示例#3
0
文件: alist.c 项目: carriercomm/epic4
/*
 * This is just a generalization of the old function  ``find_command''
 *
 * You give it an alist_item and a name, and it gives you the number of
 * items that are completed by that name, and where you could find/put that
 * item in the list.  It returns the alist_item most appropriate.
 *
 * If ``cnt'' is less than -1, then there was one exact match and one or
 *	more ambiguous matches in addition.  The exact match's location 
 *	is put into ``loc'' and its entry is returned.  The ambigous matches
 *	are (of course) immediately subsequent to it.
 *
 * If ``cnt'' is -1, then there was one exact match.  Its location is
 *	put into ``loc'' and its entry is returned.
 *
 * If ``cnt'' is zero, then there were no matches for ``name'', but ``loc''
 * 	is set to the location in the array in which you could place the
 * 	specified name in the sorted list.
 *
 * If ``cnt'' is one, then there was one command that non-ambiguously 
 * 	completes ``name''
 *
 * If ``cnt'' is greater than one, then there was exactly ``cnt'' number
 *	of entries that completed ``name'', but they are all ambiguous.
 *	The entry that is lowest alphabetically is returned, and its
 *	location is put into ``loc''.
 */
array_item *
find_array_item (array *set, const char *name, int *cnt, int *loc)
{
	size_t		len = strlen(name);
	int		c = 0, 
			pos = 0, 
			tospot, /* :-) */
			min, 
			max;
	u_32int_t	mask;
	u_32int_t	hash;

	if (set->hash == HASH_INSENSITIVE)
		hash = ci_alist_hash(name, &mask);
	else
		hash = cs_alist_hash(name, &mask);

	*cnt = 0;
	if (!set->list || !set->max)
	{
		*loc = 0;
		return NULL;
	}

	alist_searches++;

	/*
	 * The first search is a cheap refinement.  Using the hash
	 * value, find a range of symbols that have the same first
	 * four letters as 'name'.  Since we're doing all integer
	 * comparisons, its cheaper than the full blown string compares.
	 */
	/*
	 * OK, well all of that has been rolled into these two loops,
	 * designed to find the start and end of the range directly.
	 */

	tospot = max = set->max - 1;
	min = 0;

	while (max >= min)
	{
		bin_ints++;
		pos = (max - min) / 2 + min;
		c = (hash & mask) - (ARRAY_ITEM(set, pos)->hash & mask);
		if (c == 0) {
			bin_chars++;
			c = set->func(name, ARRAY_ITEM(set, pos)->name, len);
		}
		if (c == 0) {
			if (max == pos)
				break;
			max = pos;
		}
		else if (c < 0)
			tospot = max = pos - 1;
		else
			min = pos + 1;
	}

	/*
	 * If we can't find a symbol that qualifies, then we can just drop
	 * out here.  This is good because a "pass" (lookup for a symbol that
	 * does not exist) requires only cheap integer comparisons.
	 */
	if (c != 0)
	{
		if (c > 0)
			*loc = pos + 1;
		else
			*loc = pos;
		return NULL;
	}

	/*
	 * At this point, min is set to the first matching name in
	 * the range and tospot is set to a higher position than
	 * the last.  These are used to refine the next search.
	 */

	max = tospot;
	tospot = pos;

	while (max >= min)
	{
		bin_ints++;
		pos = (min - max) / 2 + max;  /* Don't ask */
		c = (hash & mask) - (ARRAY_ITEM(set, pos)->hash & mask);
		if (c == 0) {
			bin_chars++;
			c = set->func(name, ARRAY_ITEM(set, pos)->name, len);
		}
		if (c == 0) {
			if (min == pos)
				break;
			min = pos;
		}
		else if (c < 0)
			max = pos - 1;
		else
			min = pos + 1;
	}

	min = tospot;

	char_searches++;

	/*
	 * If we've gotten this far, then we've found at least
	 * one appropriate entry.  So we set *cnt to one
	 */
	*cnt = 1 + pos - min;

#if 0
	/*
	 * So we know that 'pos' is a match.  So we start 'min'
	 * at one less than 'pos' and walk downard until we find
	 * an entry that is NOT matched.
	 */
	min = pos - 1;
	while (min >= 0 && !set->func(name, ARRAY_ITEM(set, min)->name, len))
		(*cnt)++, min--, lin_chars++;
	min++;

	/*
	 * Repeat the same ordeal, except this time we walk upwards
	 * from 'pos' until we dont find a match.
	 */
	max = pos + 1;
	while (max < set->max && !set->func(name, ARRAY_ITEM(set, max)->name, len))
		(*cnt)++, max++, lin_chars++;
#endif

	/*
	 * Alphabetically, the string that would be identical to
	 * 'name' would be the first item in a string of items that
	 * all began with 'name'.  That is to say, if there is an
	 * exact match, its sitting under item 'min'.  So we check
	 * for that and whack the count appropriately.
	 */
	if (0 == (ARRAY_ITEM(set, min)->name)[len])
		*cnt *= -1;

	/*
	 * Then we tell the caller where the lowest match is,
	 * in case they want to insert here.
	 */
	if (loc)
		*loc = min;

	/*
	 * Then we return the first item that matches.
	 */
	return ARRAY_ITEM(set, min);
}