#help_index "AutoComplete/Dictionary"
public U8 *ACDDefGet(U8 *st, I64 def_num=1)
{//MAlloc str holding single dict definition of word.
	CFile		 *f;
	CHashGeneric *tmph;
	U8			 *res = NULL, *buf, *in_ptr, *st2 = MStrUtil(st, SUF_TO_UPPER);

	tmph = HashFind(st2, ac.hash_table, HTT_DICT_WORD);
	Free(st2);
	if (tmph)
	{
		if (f = FOpen(ACD_DEF_FILENAME, "r"))
		{
			buf = MAlloc(ACD_BLK_SIZE * 2 + 1);
			buf[ACD_BLK_SIZE * 2] = 0; //terminate
			FBlkRead(f, buf, tmph->user_data0 * ACD_BLK_SIZE / BLK_SIZE, ACD_BLK_SIZE * 2 / BLK_SIZE);
			FClose(f);
			in_ptr = buf;
			while (in_ptr < buf + ACD_BLK_SIZE * 2)
			{
				while (*in_ptr != ACD_WORD_CHAR && in_ptr < buf + ACD_BLK_SIZE * 2)
					in_ptr++;
				if (*in_ptr++ == ACD_WORD_CHAR)
				{
					if (!StrICompare(st, in_ptr))
					{
						while (def_num && *in_ptr != ACD_WORD_CHAR && in_ptr < buf + ACD_BLK_SIZE * 2)
						{
							if (*in_ptr == ACD_DEF_CHAR)
							{
								if (!--def_num)
									break;
								else
									in_ptr++;
							}
							else
								in_ptr++;
						}
						if (*in_ptr++ == ACD_DEF_CHAR)
						{
							res = StrNew(in_ptr);
							break;
						}
					}
				}
			}
			Free(buf);
		}
	}
	return res;
}

public U8 *ACDDefsGet(U8 *st)
{//MAlloc str with all dict definitions of word.
	CFile		 *f;
	CHashGeneric *tmph;
	U8			 *res = NULL, *buf, *in_ptr, *in_ptr2, *st2 = MStrUtil(st, SUF_TO_UPPER);

	tmph = HashFind(st2, ac.hash_table, HTT_DICT_WORD);
	Free(st2);

	if (tmph)
	{
		if (f = FOpen(ACD_DEF_FILENAME, "r"))
		{
			buf = MAlloc(ACD_BLK_SIZE * 2 + 1);
			buf[ACD_BLK_SIZE * 2] = 0; //terminate
			FBlkRead(f, buf, tmph->user_data0 * ACD_BLK_SIZE / BLK_SIZE, ACD_BLK_SIZE * 2 / BLK_SIZE);
			FClose(f);
			in_ptr = buf;
			while (in_ptr < buf + ACD_BLK_SIZE * 2)
			{
				while (*in_ptr != ACD_WORD_CHAR && in_ptr < buf + ACD_BLK_SIZE * 2)
					in_ptr++;
				if (*in_ptr++ == ACD_WORD_CHAR)
				{
					if (!StrICompare(st, in_ptr))
					{
						in_ptr2 = in_ptr;
						in_ptr--;
						while (*in_ptr2 != ACD_WORD_CHAR && in_ptr2 < buf + ACD_BLK_SIZE * 2)
						{
							in_ptr2++;
						}
						res = MAlloc(in_ptr2 + 1 - in_ptr);
						MemCopy(res, in_ptr, in_ptr2 - in_ptr);
						res[in_ptr2 - in_ptr] = ACD_END_CHAR;
						break;
					}
				}
			}
			Free(buf);
		}
	}
	return res;
}

/*Format of word list entry:
	U8 ACD_WORD_CHAR
	U8 word[] with terminating zero
	I16 block;
*/
public U8 *ACDWordPtAt(U8 *st)
{//Point to word in word list.
	I64 i;
	U8 *start = acd.word_list, *r = start, *end = acd.word_list + acd.word_list_size;

	if (!st || !*st)
		return acd.word_list;
	if (acd.word_list_size)
	{
		while (start + 3 < end)
		{
			r = (start + end) >> 1;
			while (TRUE)
			{
				while (*r != ACD_WORD_CHAR && r > acd.word_list)
					r--;
				if ((r[2] == ACD_WORD_CHAR || r[1] == ACD_WORD_CHAR)&& r - 3 > acd.word_list)
					r--;
				else
					break;
			}
			if (*r == ACD_WORD_CHAR)
			{
				i = StrICompare(st, r + 1);
				if (i < 0)
					end = r - 1;
				else if (i > 0)
					start = r + StrLen(r) + 3;
				else
					return r;
			}
			else
				break;
		}
		r = (start + end) >> 1;
		while (TRUE)
		{
			while (*r != ACD_WORD_CHAR && r > acd.word_list)
				r--;
			if ((r[2] == ACD_WORD_CHAR || r[1] == ACD_WORD_CHAR) && r - 3 > acd.word_list)
				r--;
			else
				break;
		}
		if (*r == ACD_WORD_CHAR && StrICompare(st, r + 1) > 0)
			r += StrLen(r) + 3;
	}
	if (*r == ACD_WORD_CHAR)
		return r;
	else
		return acd.word_list;
}

U0 ACDFillin(I64 n)
{
	U8 *s;
	I64 len;

	if (0 <= n < acd.num_fillins)
	{
		s = acd.fillins[n] + 1;
		len = StrLen(s);
		if (len > ac.partial_len)
			In(s + ac.partial_len);
	}
}

public U0 ACDDefsPut(CDoc *doc=NULL, U8 *st, I64 num=-1)
{//Put to doc a dictionary definition(s) of a word.
	U8 *st2, *st3;
	I64 ch, i = 0;

	if (!st)
		return;
	if (*st == ACD_WORD_CHAR)
		st++;
	DocPrint(doc, "$$WW,1$$$$RED$$%s:$$FG$$\n\n", st);
	if (num < 0)
	{
		if (st3 = ACDDefsGet(st))
		{
			st2 = st3;
			while (ch = *st2++)
			{
				switch (ch)
				{
					case ACD_WORD_CHAR:
						break;

					case ACD_DEF_CHAR:
						DocPrint(doc, "$$GREEN$$(%d)$$FG$$ %s\n", ++i, st2);
						break;

					case ACD_PRONUNCIATION_CHAR:
						DocPrint(doc, "$$LTGREEN$$%s$$FG$$\n", st2);
						break;

					case ACD_POS_CHAR:
						DocPrint(doc, "$$BLACK$$%s$$FG$$\n", st2);
						break;

					case ACD_EXTRA_CHAR:
						DocPrint(doc, "$$LTBLUE$$%s$$FG$$\n", st2);
						break;
				}
				st2 += StrLen(st2) + 1;
			}
			Free(st3);
		}
	}
	else
	{
		while (st2 = ACDDefGet(st, ++i))
		{
			if (i == num)
				DocPrint(doc, "$$GREEN$$(%d)$$FG$$ %s\n", i, st2);
			Free(st2);
		}
	}
}

U0 ACDPopUpDef(U8 *st, I64 num=-1, CTask *parent=NULL)
{
	U8 *buf;

	buf = MStrPrint("ACDDefsPut(DocPut,\"%s\",%d);View;", st, num);
	PopUp(buf, parent);
	Free(buf);
}

U0 ACDDef(I64 n, CTask *parent=NULL)
{
	if (0 <= n < acd.num_fillins)
		ACDPopUpDef(acd.fillins[n], -1, parent);
}

#help_index "AutoComplete"
U0 ACFillIn(I64 n)
{
	U8 *s;

	if (0 <= --n < ac.num_fillins)
	{
		s = ac.fillin_matches[n]->str;
		if (StrLen(s) > ac.partial_len)
			In(s + ac.partial_len);
	}
}

U0 ACMan(I64 n, CTask *parent_task=NULL)
{
	CHashAC *tmpw;
	CHashSrcSym *tmph;

	if (0 <= --n < ac.num_fillins &&
			(tmpw = ac.fillin_matches[n]) && (tmph = HashFind(tmpw->str, Fs->hash_table, HTG_SRC_SYM)) && tmph->src_link)
		PopUpEd(tmph->src_link, parent_task);
}
