U8 *Tabs2Spaces(U8 *src)
{//MAlloc str with tabs to spaces.
	I64 ch, i, j, l = StrLen(src) << 1 + 2, col = 0;
	U8 *dst = MAlloc(l), *tmp;

	while (ch = *src++)
	{
		if (ch == '\t')
		{
			j = (col + 8) & ~7;
			for (i = col; i < j; i++)
			{
				dst[i] = CH_SPACE;
				if (i >= l - 2)
				{
					tmp = MAlloc(l << 1);
					MemCopy(tmp, dst, i + 1);
					Free(dst);
					l <<= 1;
					dst = tmp;
				}
			}
			col = j;
		}
		else
		{
			dst[col] = ch;
			if (col >= l - 2)
			{
				tmp = MAlloc(l << 1);
				MemCopy(tmp, dst, col + 1);
				Free(dst);
				l <<= 1;
				dst = tmp;
			}
			col++;
		}
	}
	dst[col] = 0;

	return dst;
}

U8 *ScaleIndent(U8 *src, F64 indent_scale_factor)
{//MAlloced str.	8*0.25-->2 or 8*2.0-->16
	I64 ch, i, col = 0;
	U8 *dst, *dst2;

	while (ch = *src++)
	{
		if (ch == '\t')
			col = (col + 8) & -0x8;
		else if (ch == CH_SPACE)
			col++;
		else
			break;
	}
	src--;
	col = Round(indent_scale_factor * col);
	dst = dst2 = MAlloc(StrLen(src) + col / 8 + col & 7 + 1);
	for (i = col / 8; i > 0; i--)
		*dst2++ = '\t';
	for (i = col & 7; i > 0; i--)
		*dst2++ = CH_SPACE;
	StrCopy(dst2, src);

	return dst;
}

U8 *MStrUtil(U8 *src, I64 flags, F64 indent_scale_factor=0)
{//MAlloc $LK,"StrUtil",A="MN:StrUtil"$().
	U8 *dst = StrNew(src), *dst2, *tmp;

	StrUtil(dst, flags);
	if (flags & SUF_T2S)
	{
		tmp = Tabs2Spaces(dst);
		Free(dst);
		dst = tmp;
	}
	if (flags & SUF_SCALE_INDENT)
		dst2 = ScaleIndent(dst, indent_scale_factor);
	else
		dst2 = StrNew(dst); //Shorten to just right size.
	Free(dst);

	return dst2;
}

U0 GetOutOfDollar()
{//If a $$ has been printed, print another $$ to exit mode.
	CDoc *doc;

	if (IsRaw)
	{
		if (text.raw_flags & RAWF_IN_DOLLAR)
			'$$';
	}
	else
	{
		if (fp_doc_put && (doc = (*fp_doc_put)(Fs)) && doc->flags & DOCF_IN_DOLLAR)
			'$$';
	}
}

Bool YorN()
{//Wait for user to answer Y or N.
	I64 ch;

	"(y or n)? ";
	while (TRUE)
	{
		ch = ToUpper(CharGet(, FALSE));
		if (ch == 'Y')
		{
			"$$PT$$YES$$FG$$\n";
			return TRUE;
		}
		else if (ch == 'N')
		{
			"$$PT$$NO$$FG$$\n";
			return FALSE;
		}
	}
}

I64 PressAKey()
{//Print "Press a key" and wait for non-zero $LK,"ASCII",A="MN:CH_CTRLA"$ key.
	"$$BK,1$$PRESS A KEY$$BK,0$$\n";
	return CharGet(, FALSE);
}

Bool AreYouSure()
{//Print "Are you sure" and waits for Y or N.
	"ARE YOU SURE ";
	return YorN;
}

U0 Help()
{//Debug help or master help index file.
	if (IsDebugMode)
		DebugHelp;
	else
		PopUp("Type(\"::/Doc/HelpIndex.DD\");DocTop;View;");
}

U0 FlagsScan(U8 *_dst_flags, U8 *list, U8 *src)
{/*More than 64 flags. Flags passed by ref.

Examples:
$LK,"FlagsScan",A="FF:::/Zenith/Utils/Find.CC,FlagsScan:2"$(&fuf_flags,Define("ST_FILE_UTIL_FLAGS"),fu_flags);

I64 flags=0;
FlagsScan(&flags,"R\0L\0Dump\0Scan\0","+Dump-R"); //Sets Bit#2, Clears Bit#0.
*/
	I64 i;
	U8 *buf, *ptr;

	if (src)
	{
		buf = MAlloc(StrLen(src) + 1);
		while (*src)
		{
			while (*src && *src != '+' && *src != '-')
				src++;
			if (*src == '+')
			{
				src++;
				if (*src)
				{
					ptr = buf;
					while (*src && *src != '+' && *src != '-' && *src != CH_SPACE)
						*ptr++ = *src++;
					*ptr = 0;
					i = ListMatch(buf, list);
					if (i >= 0)
						LBts(_dst_flags, i);
					else
					{
						Free(buf);
						throw('ScanFlag');
					}
				}
			}
			else if (*src == '-')
			{
				src++;
				if (*src)
				{
					ptr = buf;
					while (*src && *src != '+' && *src != '-' && *src != CH_SPACE)
						*ptr++ = *src++;
					*ptr = 0;
					i = ListMatch(buf, list);
					if (i >= 0)
						LBtr(_dst_flags, i);
					else
					{
						Free(buf);
						throw('ScanFlag');
					}
				}
			}
		}
		Free(buf);
	}
}

U8 *FlagsStrPrint(U8 *dst, U8 *list, I64 flags, Bool print_all=FALSE, I64 print_all_length=0)
{//Only 64 flags. Flags passed by value. print_all will print false flags using `-`.
//Specify print_all_length (list length) if print_all is true.
	I64 i = 0;

	*dst = 0;
	if (!print_all_length)
		print_all_length =  64;
	while (i < print_all_length)
	{
		if (Bt(&flags, i))
			CatPrint(dst, "+%z", i, list);
		else if (print_all)
			CatPrint(dst, "-%z", i, list);
		i++;
	}

	return dst;
}
