C++: AHK source code: demo functions

Talk about things C/C++, some related to AutoHotkey
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

C++: AHK source code: demo functions

21 Aug 2018, 01:04

- Here are some demo AHK functions written in C++.
- They are intended for teaching purposes.
- 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.

- A known issue that needs to be addressed for some functions:
functions interpreting non-numeric strings as 0 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 14&t=54365

- Built-in functions can be added to AutoHotkey by changing 3 files:
- Trivial additions are made to script.h and script.cpp.
- The function proper is added to script2.cpp.
Last edited by jeeswg on 25 Aug 2018, 22:27, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

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

21 Aug 2018, 01:11

- A known issue that needs to be addressed for some functions:
You can use ParamIndexToNumber instead of ParamIndexToInt and take whatever measures you like on invalid input.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

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

21 Aug 2018, 01:13

Code: Select all

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

for AHK v1: function names and parameters:

Add(Num1, Num2)
EmptyFloat()
EmptyInteger()
EmptyString()
ReturnFloat()
ReturnInteger()
ReturnString()
StrConcat(Text1, Text2)
StrLeft(Text, Num)
StrRight(Text, Num)
StrTrimLeft(Text, Num)
StrTrimRight(Text, Num)
Sum(Params*)

note: Add could be easily modified to become Sub/Mult/Div
note: Sum could be easily modified to become Product

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

[script.h]

BIF_DECL(BIF_Add);
BIF_DECL(BIF_EmptyFloat);
BIF_DECL(BIF_EmptyInteger);
BIF_DECL(BIF_EmptyString);
BIF_DECL(BIF_ReturnFloat);
BIF_DECL(BIF_ReturnInteger);
BIF_DECL(BIF_ReturnString);
BIF_DECL(BIF_StrConcat);
BIF_DECL(BIF_StrLeft);
BIF_DECL(BIF_StrRight);
BIF_DECL(BIF_StrTrimLeft);
BIF_DECL(BIF_StrTrimRight);
BIF_DECL(BIF_Sum);

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

[script.cpp]

	else if (!_tcsicmp(func_name, _T("Add")))
	{
		bif = BIF_Add;
		min_params = 2;
		max_params = 2;
	}
	else if (!_tcsicmp(func_name, _T("EmptyFloat")))
	{
		bif = BIF_EmptyFloat;
		min_params = 0;
		max_params = 10000; // An arbitrarily high limit that will never realistically be reached.
	}
	else if (!_tcsicmp(func_name, _T("EmptyInteger")))
	{
		bif = BIF_EmptyInteger;
		min_params = 0;
		max_params = 10000; // An arbitrarily high limit that will never realistically be reached.
	}
	else if (!_tcsicmp(func_name, _T("EmptyString")))
	{
		bif = BIF_EmptyString;
		min_params = 0;
		max_params = 10000; // An arbitrarily high limit that will never realistically be reached.
	}
	else if (!_tcsicmp(func_name, _T("ReturnFloat")))
	{
		bif = BIF_ReturnFloat;
		min_params = 0;
		max_params = 10000; // An arbitrarily high limit that will never realistically be reached.
	}
	else if (!_tcsicmp(func_name, _T("ReturnInteger")))
	{
		bif = BIF_ReturnInteger;
		min_params = 0;
		max_params = 10000; // An arbitrarily high limit that will never realistically be reached.
	}
	else if (!_tcsicmp(func_name, _T("ReturnString")))
	{
		bif = BIF_ReturnString;
		min_params = 0;
		max_params = 10000; // An arbitrarily high limit that will never realistically be reached.
	}
	else if (!_tcsicmp(func_name, _T("StrConcat")))
	{
		bif = BIF_StrConcat;
		min_params = 2;
		max_params = 2;
	}
	else if (!_tcsicmp(func_name, _T("StrLeft")))
	{
		bif = BIF_StrLeft;
		min_params = 2;
		max_params = 2;
	}
	else if (!_tcsicmp(func_name, _T("StrRight")))
	{
		bif = BIF_StrRight;
		min_params = 2;
		max_params = 2;
	}
	else if (!_tcsicmp(func_name, _T("StrTrimLeft")))
	{
		bif = BIF_StrTrimLeft;
		min_params = 2;
		max_params = 2;
	}
	else if (!_tcsicmp(func_name, _T("StrTrimRight")))
	{
		bif = BIF_StrTrimRight;
		min_params = 2;
		max_params = 2;
	}
	else if (!_tcsicmp(func_name, _T("Sum")))
	{
		bif = BIF_Sum;
		max_params = 10000; // An arbitrarily high limit that will never realistically be reached.
	}

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

[script2.cpp]

BIF_DECL(BIF_Add)
{
	ExprTokenType param0, param1;
	if (!ParamIndexToNumber(0, param0) || !ParamIndexToNumber(1, param1)) // Non-operand or non-numeric string.
	{
		aResultToken.symbol = SYM_STRING;
		aResultToken.marker = _T("");
		return;
	}
	if (param0.symbol == SYM_INTEGER && param1.symbol == SYM_INTEGER)
	{
		aResultToken.symbol = SYM_INTEGER;
		aResultToken.value_int64 = param0.value_int64 + param1.value_int64;
	}
	else // At least one is a floating point number.
	{
		double double1 = TokenToDouble(param0);
		double double2 = TokenToDouble(param1);
		aResultToken.symbol = SYM_FLOAT;
		aResultToken.value_double = double1 + double2;
	}
}

BIF_DECL(BIF_EmptyFloat)
{
    //returns 0
	aResultToken.symbol = SYM_FLOAT;
}

BIF_DECL(BIF_EmptyInteger)
{
    //returned a 17-digit positive integer during my tests
	aResultToken.symbol = SYM_INTEGER; //line not needed
}

BIF_DECL(BIF_EmptyString)
{
	//returns the function name
	aResultToken.symbol = SYM_STRING;
}

BIF_DECL(BIF_ReturnFloat)
{
	aResultToken.symbol = SYM_FLOAT;
	aResultToken.value_double = 42;
}

BIF_DECL(BIF_ReturnInteger)
{
	aResultToken.symbol = SYM_INTEGER; //line not needed
	aResultToken.value_int64 = 42;
}

BIF_DECL(BIF_ReturnString)
{
	aResultToken.symbol = SYM_STRING;
	aResultToken.marker = _T("hello world");
}

BIF_DECL(BIF_StrConcat)
{
	aResultToken.symbol = SYM_STRING;
	int len0 = (int)_tcslen(ParamIndexToString(0));
	int len1 = (int)_tcslen(ParamIndexToString(1));
	if (len0 + len1 == 0)
	{
		aResultToken.marker = _T("");
		return;
	}

	TCHAR *output = new TCHAR[len0+len1+1];
	tmemcpy(output, ParamIndexToString(0), len0);
	tmemcpy(output+len0, ParamIndexToString(1), len1+1);
	aResultToken.marker = output;
}

BIF_DECL(BIF_StrLeft)
{
	// Set default return value in case of early return.
	aResultToken.symbol = SYM_STRING;
	aResultToken.marker = _T("");

	TCHAR haystack_buf[MAX_NUMBER_SIZE]; // A separate buf because aResultToken.buf is sometimes used to store the result.
	LPTSTR haystack = ParamIndexToString(0, haystack_buf); // Remember that aResultToken.buf is part of a union, though in this case there's no danger of overwriting it since our result will always be of STRING type (not int or float).
	INT_PTR haystack_length = (INT_PTR)ParamIndexLength(0, haystack);

	INT_PTR extract_length = (INT_PTR)ParamIndexToInt64(1);
	if (extract_length < 1)
		return;

	if (!TokenSetResult(aResultToken, haystack, extract_length))
	{
		// Yield the empty string (a default set higher above).
	}
}

BIF_DECL(BIF_StrRight)
{
	// Set default return value in case of early return.
	aResultToken.symbol = SYM_STRING;
	aResultToken.marker = _T("");

	TCHAR haystack_buf[MAX_NUMBER_SIZE]; // A separate buf because aResultToken.buf is sometimes used to store the result.
	LPTSTR haystack = ParamIndexToString(0, haystack_buf); // Remember that aResultToken.buf is part of a union, though in this case there's no danger of overwriting it since our result will always be of STRING type (not int or float).
	INT_PTR haystack_length = (INT_PTR)ParamIndexLength(0, haystack);

	INT_PTR extract_length = (INT_PTR)ParamIndexToInt64(1);
	if (extract_length < 1)
		return;

	if (extract_length > haystack_length)
	        extract_length = haystack_length;
	LPTSTR result = haystack + haystack_length - extract_length; // This is the result except for the possible need to truncate it below.

	if (!TokenSetResult(aResultToken, result, extract_length))
	{
		// Yield the empty string (a default set higher above).
	}
}

BIF_DECL(BIF_StrTrimLeft)
{
	//causing crashes (check if 2nd param looks numeric)
	//if (!TokenToDoubleOrInt64(*aParam[1], aResultToken)) // "Cast" token to Int64/Double depending on whether it has a decimal point.
	//    return;

	// Set default return value in case of early return.
	aResultToken.symbol = SYM_STRING;
	aResultToken.marker = _T("");

	TCHAR haystack_buf[MAX_NUMBER_SIZE]; // A separate buf because aResultToken.buf is sometimes used to store the result.
	LPTSTR haystack = ParamIndexToString(0, haystack_buf); // Remember that aResultToken.buf is part of a union, though in this case there's no danger of overwriting it since our result will always be of STRING type (not int or float).
	INT_PTR haystack_length = (INT_PTR)ParamIndexLength(0, haystack);

	INT_PTR crop_length = (INT_PTR)ParamIndexToInt64(1);
	if (crop_length >= haystack_length)
		return;

	LPTSTR result = haystack + crop_length; // This is the result except for the possible need to truncate it below.

	if (!TokenSetResult(aResultToken, result, haystack_length - crop_length))
	{
		// Yield the empty string (a default set higher above).
	}
}

BIF_DECL(BIF_StrTrimRight)
{
	//causing crashes (check if 2nd param looks numeric)
	//if (!TokenToDoubleOrInt64(*aParam[1], aResultToken)) // "Cast" token to Int64/Double depending on whether it has a decimal point.
	//    return;

	// Set default return value in case of early return.
	aResultToken.symbol = SYM_STRING;
	aResultToken.marker = _T("");

	TCHAR haystack_buf[MAX_NUMBER_SIZE]; // A separate buf because aResultToken.buf is sometimes used to store the result.
	LPTSTR haystack = ParamIndexToString(0, haystack_buf); // Remember that aResultToken.buf is part of a union, though in this case there's no danger of overwriting it since our result will always be of STRING type (not int or float).
	INT_PTR haystack_length = (INT_PTR)ParamIndexLength(0, haystack);

	INT_PTR crop_length = (INT_PTR)ParamIndexToInt64(1);
	if (crop_length < 0 || crop_length >= haystack_length)
		return;

	if (!TokenSetResult(aResultToken, haystack, haystack_length-crop_length))
	{
		// Yield the empty string (a default set higher above).
	}
}

BIF_DECL(BIF_Sum)
{
	// Supports one or more parameters.
	// Load-time validation has already ensured there is at least one parameter.
	ExprTokenType param;
	__int64 i_sum = 0;
	double d_sum = 0;
	bool d_empty = TRUE;
	for (int i = 0; i < aParamCount; ++i)
	{
		ParamIndexToNumber(i, param);
		switch (param.symbol)
		{
			case SYM_INTEGER:
				i_sum += param.value_int64;
				break;
			case SYM_FLOAT:
				d_sum += param.value_double;
				if (d_empty)
					d_empty = FALSE;
				break;
			default: // Non-operand or non-numeric string.
				aResultToken.symbol = SYM_STRING;
				aResultToken.marker = _T("");
				return; // Return a blank value to indicate the problem.
		}
	}

	if (d_empty)
	{
		aResultToken.symbol = SYM_INTEGER;
		aResultToken.value_int64 = i_sum;
	}
	else
	{
		aResultToken.symbol = SYM_FLOAT;
		aResultToken.value_double = d_sum + (double)i_sum;
	}
}

==================================================
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
YMP2
Posts: 48
Joined: 20 Apr 2014, 06:55

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

22 Aug 2018, 04:25

jeeswg wrote: - Functions can be added to AutoHotkey by changing 3 files:
- Trivial additions are made to script.h and script.cpp.
- The function proper is added to script2.cpp.
It's better to keep your functions in a separate file.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

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

25 Aug 2018, 22:30

- I've edited the OP to state 'Built-in functions can be ...'.
- This thread is about adding built-in functions via C++, and creating an alternate version of AutoHotkey.exe, and not about adding custom functions via AHK code.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
YMP2
Posts: 48
Joined: 20 Apr 2014, 06:55

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

25 Aug 2018, 22:38

That was clear from the very beginning.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

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

25 Aug 2018, 22:40

- In that case, please explain your point.
- I'm editing the AutoHotkey source code as it is.
- To change which file contains what would involve changing the entire source code. Or do you mean something more specific? Thanks.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
YMP2
Posts: 48
Joined: 20 Apr 2014, 06:55

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

26 Aug 2018, 01:29

I meant it would be best to keep changes to the original source as small as possible. For instance by keeping the additional code in separate files and #including them in the source files. Or just adding your files to the AutoHotkey project in VisualStudio. That way it would be easier to transfer your additions from an older version of AHK to a newer one.

Return to “C/C++”

Who is online

Users browsing this forum: No registered users and 10 guests