C++: AHK source code: potential functions

Discuss other programming languages besides AutoHotkey
User avatar
jeeswg
Posts: 5286
Joined: 19 Dec 2016, 01:58
Location: UK

C++: AHK source code: potential functions

21 Aug 2018, 01:21

- Here are some potential AHK functions written in C++.
- Once inserted into the source code, and compiled, they work just like any other built-in functions.
- I would welcome people to post better more efficient versions of the functions.
User avatar
jeeswg
Posts: 5286
Joined: 19 Dec 2016, 01:58
Location: UK

Re: C++: AHK source code: potential functions

21 Aug 2018, 01:22

Code: Select all

==================================================

for AHK v1: function names and parameters:

ATan2(NumY, NumX)
Between(Num, Lim1, Lim2)
[FloorCeil] Ceil(Num, DP:=0)
[FloorCeil] Floor(Num, DP:=0)
IsNum(Num)
Log(Num, Base:=10)
NoOp(Params*)
Num(Num)
Pow(Num, Power)
Sign(Num)
StrCount(Haystack, Needle, CaseSen:="", StartPos:=1)
StrJoin(Sep, Params*)
StrRept(Text, Num)

- note: BIF_FloorCeil would be amended
- note: BIF_Log would be used for Log, instead of BIF_SqrtLogLn
- note: I wouldn't mind if StrCount's StartPos parameter was removed for now
- note: For StrCount, a decision would be needed on how to handle a negative StartPos ( I would recommend the AHK v2 behaviour for AHK v1 and AHK v2)
- note: StrJoin takes a string 'Sep', however, perhaps functionality for passing a linear array could be added, for alternating separators

- IsNum:
- Float/Integer/numeric-looking string return 1, else 0.

- Num:
- Float/Integer unchanged, numeric-looking string to Float/Integer, else error.
- I've since thought of adding a second parameter: Default.
- If present, instead of an error, the Default would be returned e.g. 0, or "".

==================================================

[script.h]

BIF_DECL(BIF_ATan2);
BIF_DECL(BIF_Between);
BIF_DECL(BIF_FloorCeil);
BIF_DECL(BIF_IsNum);
BIF_DECL(BIF_Log);
BIF_DECL(BIF_NoOp);
BIF_DECL(BIF_Num);
BIF_DECL(BIF_Pow);
BIF_DECL(BIF_Sign);
BIF_DECL(BIF_StrCount);
BIF_DECL(BIF_StrJoin);
BIF_DECL(BIF_StrRept);

==================================================

[script.cpp]

	else if (!_tcsicmp(func_name, _T("ATan2")))
	{
		bif = BIF_ATan2;
		min_params = 2;
		max_params = 2;
	}
	else if (!_tcsicmp(func_name, _T("Between")))
	{
		bif = BIF_Between;
		min_params = 3;
		max_params = 3;
	}
	else if (!_tcsicmp(func_name, _T("Floor")) || !_tcsicmp(func_name, _T("Ceil")))
	{
		bif = BIF_FloorCeil;
		max_params = 2;
	}
	else if (!_tcsicmp(func_name, _T("IsNum")))
	{
		bif = BIF_IsNum;
	}
	else if (!_tcsicmp(func_name, _T("Log")))
	{
		bif = BIF_Log;
		max_params = 2;
	}
	else if (!_tcsicmp(func_name, _T("NoOp")))
	{
		bif = BIF_NoOp;
		min_params = 0;
		max_params = 10000; // An arbitrarily high limit that will never realistically be reached.
	}
	else if (!_tcsicmp(func_name, _T("Num")))
	{
		bif = BIF_Num;
	}
	else if (!_tcsicmp(func_name, _T("Pow")))
	{
		bif = BIF_Pow;
		min_params = 2;
		max_params = 2;
	}
	else if (!_tcsicmp(func_name, _T("Sign")))
	{
		bif = BIF_Sign;
	}
	else if (!_tcsicmp(func_name, _T("StrCount")))
	{
		bif = BIF_StrCount;
		min_params = 2;
		max_params = 4;
	}
	else if (!_tcsicmp(func_name, _T("StrJoin")))
	{
		bif = BIF_StrJoin;
		min_params = 2;
		max_params = 10000; // An arbitrarily high limit that will never realistically be reached.
	}
	else if (!_tcsicmp(func_name, _T("StrRept")))
	{
		bif = BIF_StrRept;
		min_params = 2;
		max_params = 2;
	}

==================================================

[script2.cpp]

BIF_DECL(BIF_ATan2)
{
	// For simplicity and backward compatibility, a numeric result is always returned (even if the input
	// is non-numeric or an empty string).
	aResultToken.symbol = SYM_FLOAT;
	aResultToken.value_double = qmathAtan2(ParamIndexToDouble(0), ParamIndexToDouble(1));
}

BIF_DECL(BIF_Between)
{
	if (!TokenToDoubleOrInt64(*aParam[0], aResultToken)) // "Cast" token to Int64/Double depending on whether it has a decimal point.
		return;
	if (!TokenToDoubleOrInt64(*aParam[1], aResultToken)) // "Cast" token to Int64/Double depending on whether it has a decimal point.
		return;
	if (!TokenToDoubleOrInt64(*aParam[2], aResultToken)) // "Cast" token to Int64/Double depending on whether it has a decimal point.
		return;

	double value = ParamIndexToDouble(0);
	double min = ParamIndexToDouble(1);
	double max = ParamIndexToDouble(2);

	aResultToken.symbol = SYM_INTEGER;
	if (min <= value && value <= max)
		aResultToken.value_int64 = 1;
	else
		aResultToken.value_int64 = 0;
}

BIF_DECL(BIF_FloorCeil)
{
	LPTSTR buf = aResultToken.buf; // Must be saved early since below overwrites the union (better maintainability too).

	int param2;
	double multiplier;
	if (aParamCount > 1)
	{
		param2 = ParamIndexToInt(1);
		multiplier = qmathPow(10, param2);
	}
	else // Omitting the parameter is the same as explicitly specifying 0 for it.
	{
		param2 = 0;
		multiplier = 1;
	}
	double value = ParamIndexToDouble(0);
	aResultToken.value_double = ((ctoupper(aResultToken.marker[0]) == 'F') ? qmathFloor(value * multiplier)
		: qmathCeil(value * multiplier)) / multiplier;

	if (param2 > 0) // aResultToken.value_double already contains the result.
	{
		_stprintf(buf, _T("%0.*f"), param2, aResultToken.value_double); // %f can handle doubles in MSVC++.
		aResultToken.marker = buf;
		aResultToken.symbol = SYM_STRING;
	}
	else
		aResultToken.value_int64 = (__int64)(aResultToken.value_double + (aResultToken.value_double > 0 ? 0.2 : -0.2));
}

BIF_DECL(BIF_IsNum)
{
	if (!TokenToDoubleOrInt64(*aParam[0], aResultToken)) // "Cast" token to Int64/Double depending on whether it has a decimal point.
	{
		aResultToken.symbol = SYM_INTEGER;
		aResultToken.value_int64 = 0;
	}
	else
	{
		aResultToken.symbol = SYM_INTEGER;
		aResultToken.value_int64 = 1;
	}
}

BIF_DECL(BIF_Log)
{
	double value = ParamIndexToDouble(0);
	double base = ParamIndexIsOmitted(1) ? 10 : ParamIndexToDouble(1);
	if (value < 0 || base < 0) // Result is undefined in these cases, so make blank to indicate.
	{
		aResultToken.symbol = SYM_STRING;
		aResultToken.marker = _T("");
	}
	else if (base == 10)
	{
		aResultToken.symbol = SYM_FLOAT;
		aResultToken.value_double = qmathLog10(value);
	}
	else
	{
		aResultToken.symbol = SYM_FLOAT;
		aResultToken.value_double = qmathLog10(value)/qmathLog10(base);
		//aResultToken.value_double = qmathLog(value)/qmathLog(base);
	}
}

BIF_DECL(BIF_NoOp)
{
	aResultToken.symbol = SYM_STRING;
	aResultToken.marker = _T("");
}

BIF_DECL(BIF_Num)
{
	if (!TokenToDoubleOrInt64(*aParam[0], aResultToken)) // "Cast" token to Int64/Double depending on whether it has a decimal point.
	{
		aResultToken.symbol = SYM_STRING;
		aResultToken.marker = _T("");
	}
}

BIF_DECL(BIF_Pow)
{
	double value_double1 = ParamIndexToDouble(0);
	double value_double2 = ParamIndexToDouble(1);
	bool value1_was_negative = (value_double1 < 0);
	if (value_double1 == 0.0 && value_double2 < 0  // In essence, this is divide-by-zero.
		|| value1_was_negative && qmathFmod(value_double2, 1.0) != 0.0) // Negative base but exponent isn't close enough to being an integer: unsupported (to simplify code).
	{
		aResultToken.symbol = SYM_STRING;
		aResultToken.marker = _T("");
		return;
	}
	// Otherwise:
	if (value1_was_negative)
		value_double1 = -value_double1; // Force a positive due to the limitations of qmathPow().
	double result_double = qmathPow(value_double1, value_double2);
	if (value1_was_negative && qmathFabs(qmathFmod(value_double2, 2.0)) == 1.0) // Negative base and exactly-odd exponent (otherwise, it can only be zero or even because if not it would have returned higher above).
		result_double = -result_double;
	if (qmathFloor(result_double) == result_double)
	{
		aResultToken.symbol = SYM_INTEGER;
		aResultToken.value_int64 = (__int64)result_double;
	}
	else
	{
		aResultToken.symbol = SYM_FLOAT;
		aResultToken.value_double = result_double;
	}
}

BIF_DECL(BIF_Sign)
{
	if (!TokenToDoubleOrInt64(*aParam[0], aResultToken)) // "Cast" token to Int64/Double depending on whether it has a decimal point.
		return;

	double value = ParamIndexToDouble(0);
	aResultToken.symbol = SYM_INTEGER;
	if (value > 0)
		aResultToken.value_int64 = 1;
	else if (value < 0)
		aResultToken.value_int64 = -1;
	else
		aResultToken.value_int64 = 0;
}

BIF_DECL(BIF_StrCount)
{
	TCHAR old_buf[MAX_NUMBER_SIZE], new_buf[MAX_NUMBER_SIZE];
	// Must use aResultToken.buf for source in case StrReplace() performs no replacements:
	LPTSTR source = ParamIndexToString(0, aResultToken.buf);	// Parameter #1: Haystack
	size_t length = ParamIndexLength(0, source);
	LPTSTR oldstr = ParamIndexToString(1, old_buf);				// Parameter #2: SearchText
	//LPTSTR newstr = ParamIndexToOptionalString(2, new_buf);		// Parameter #3: ReplaceText
	LPTSTR newstr = new_buf;
	//UINT replacement_limit = (UINT)ParamIndexToOptionalInt64(4, UINT_MAX); // Parameter #5: Limit
	UINT replacement_limit = (UINT)-1; // Parameter #5: Limit
	int start_pos = ParamIndexIsOmitted(3) ? 0 : ParamIndexToInt(3)-1;

	LPTSTR dest;
	UINT found_count;
	if (ParamIndexIsOmitted(2))
		found_count = StrReplace(source+start_pos, oldstr, newstr, (StringCaseSenseType)g->StringCaseSense
		, replacement_limit, -1, &dest, &length);
	else
	{
		int case_sen = ParamIndexToInt(2);
		if (case_sen == 1 || case_sen == 0)
			found_count = StrReplace(source+start_pos, oldstr, newstr, (StringCaseSenseType)case_sen
			, replacement_limit, -1, &dest, &length);
	}

	if (!dest) // Failure due to out of memory.
	{
		aResult = g_script.ScriptError(ERR_OUTOFMEM);
		return;
	}

	//aResultToken.symbol = SYM_STRING;
	//aResultToken.marker = dest;

	//if (dest != source) // StrReplace() allocated new memory rather than returning "source" to us unaltered.
	//{
	//	aResultToken.mem_to_free = dest; // Let caller know it needs to be freed.
	//	aResultToken.marker_length = length; // Must always be set if using mem_to_free.
	//}

	aResultToken.symbol = SYM_INTEGER;
	aResultToken.value_int64 = (__int64)found_count;
}

BIF_DECL(BIF_StrJoin)
{
	aResultToken.symbol = SYM_STRING;
	if (aParamCount < 2)
	{
		aResultToken.marker = _T("");
		return;
	}

	int len_sep = (int)_tcslen(ParamIndexToString(0));
	TCHAR *sep = new TCHAR[len_sep+1];
	tmemcpy(sep, ParamIndexToString(0), len_sep+1);

	int len = 0;
	for (int i = 1; i < aParamCount; ++i)
		len += (int)_tcslen(ParamIndexToString(i));

	int len_out = len+len_sep*(aParamCount-2)+1;
	TCHAR *output = new TCHAR[len_out];

	len = 0;
	int len_temp;
	for (int i = 1; i < aParamCount-1; ++i)
	{
		len_temp = _tcslen(ParamIndexToString(i));
		tmemcpy(output+len, ParamIndexToString(i), len_temp);
		tmemcpy(output+len+len_temp, sep, len_sep);
		len += len_temp+len_sep;
	}
	len_temp = _tcslen(ParamIndexToString(aParamCount-1));
	tmemcpy(output+len, ParamIndexToString(aParamCount-1), len_temp);

	*(output+len_out-1) = '\0';
	aResultToken.marker = output;
}

BIF_DECL(BIF_StrRept)
{
	aResultToken.symbol = SYM_STRING;
	int len = (int)_tcslen(ParamIndexToString(0));
	int count = (int)ParamIndexToInt64(1);
	if (count < 1)
	{
		aResultToken.marker = _T("");
		return;
	}

	int size = len*count+1;
	TCHAR *output = new TCHAR[size];
	for (int i = 0; i <= count-1; i++)
		tmemcpy(output+i*len, ParamIndexToString(0), len);
	*(output+size-1) = '\0';
	aResultToken.marker = output;
}

==================================================

Return to “Other Programming Languages”

Who is online

Users browsing this forum: No registered users and 3 guests