C++: AHK source code: demo functions

Post a reply


In an effort to prevent automatic submissions, we require that you complete the following challenge.
Smilies
:D :) ;) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :!: :?: :idea: :| :mrgreen: :geek: :ugeek: :arrow: :angel: :clap: :crazy: :eh: :lolno: :problem: :shh: :shifty: :sick: :silent: :think: :thumbup: :thumbdown: :salute: :wave: :wtf: :yawn: :facepalm: :bravo: :dance: :beard: :morebeard: :xmas: :HeHe: :trollface: :cookie: :rainbow: :monkeysee: :monkeysay: :happybday: :headwall: :offtopic: :superhappy: :terms: :beer:
View more smilies

BBCode is ON
[img] is OFF
[flash] is OFF
[url] is ON
Smilies are ON

Topic review
   

Expand view Topic review: C++: AHK source code: demo functions

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

Post by YMP2 » 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.

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

Post by jeeswg » 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.

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

Post by YMP2 » 25 Aug 2018, 22:38

That was clear from the very beginning.

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

Post by jeeswg » 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.

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

Post by YMP2 » 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.

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

Post by jeeswg » 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;
	}
}

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

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

Post by Helgef » 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.

C++: AHK source code: demo functions

Post by jeeswg » 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.

Top