######################## RE function library ############################################
# LIB: misha_std_re_func_lib
################################################################################
# $Revision: 1.2 $
# $Author: drajovic $
# $Date: 2004/11/07 22:26:27 $
# $Source: C:/Archive/FRAMEWORK/EMOS_GPL/STD/misha_std_re_func_lib/script,v $
################################################################################
#/***
#* Regular expression functions search and match for WinRunner.
#*<p>
#* Copyright (c) 2003 Misha Verplak
#*<p>
#* Supporting regex++ c++ library at www.boost.org:
#* Copyright (c) 1998-2001 Dr John Maddock
#*<p>
#* Permission is granted to use, modify and redistribute this
#* software provided both copyrights appear in all copies.
#*<p>
#* This script and dll provides WinRunner with perl-like
#* regular expression search and match functions, to supplement
#* the limited builtin function match() and add GUI properties
#* "label_like" and "id_like" for window recognition.
#*<p>
#* Known bugs:
#* <ul>
#* <li> Garbage in re can cause regex library to crash</li>
#* </ul>
#* @author Misha Verplack
#* @version  0.2  2003-01-21
#*
#* @see <a href="readme.txt">Readme</a>
#* @see <a href="re_sample.tsl">sample</a>
#* @see <a href="re_startup.tsl">startup</a>
#* @see <a href="syntax.html">Regex syntax description</a>
#*/

# regular expressions from DLL

#/**
#* Match a regular expression to a whole string.
#* Submatch results in 'detail', use re_get_details() or re_get_match().
#* @param str string to search
#* @param re regular expression
#* @param m_pos matched position
#* @param m_len matched length
#* @param detail detail
#* @return 0 = no match, 1 = found match, gets position and length
#*/
extern int re_match(string str, string re, out int m_pos, out int m_len, inout string detail <252>);
#/**
#* Search a string for a regular expression.
#* Submatch results in 'detail', use re_get_details() or re_get_match().
#* @param str string to search
#* @param re regular expression
#* @param m_pos matched position
#* @param m_len matched length
#* @param detail detail
#* @return 0 = no match, 1 = found match, gets position and length
#*/
extern int re_search(string str, string re, out int m_pos, out int m_len, inout string detail <252>);

#/**
#* initialises the re_func
#*/
public function re_func_init()
{
	auto re_func_dll;

	# replace with location of dll
	re_func_dll = getvar("testname") & "\\re_func.dll";

	# to access exported functions
	load_dll(re_func_dll);

	# to use re's in a GUI property
	add_record_attr("label_like", re_func_dll, "re_query_label", "re_verify_label");
	add_record_attr("id_like", re_func_dll, "re_query_id", "re_verify_id");


	# function generator declarations

	generator_add_function("re_search","Search a string for a regular expression.\n"&
	"Returns 0 no match, 1 found match, gets position and length.\n"&
	"Submatch results in 'detail', use re_get_details() or re_get_match().",5,
	"search_string","type_edit","\"string to search\"",
	"regular_expression","type_edit","\"regexp\"", "Out position","type_edit","position",
	"Out length","type_edit","len", "Out detail","type_edit","detail");
	generator_add_category("regex");
	generator_add_function_to_category("regex","re_search");
	generator_set_default_function("regex","re_search");

	generator_add_function("re_match","Match a regular expression to a whole string.\n"&
	"Returns 0 no match, 1 found match, gets position and length.\n"&
	"Submatch results in 'detail', use re_get_details() or re_get_match().",5,
	"match_string","type_edit","\"string to match\"",
	"regular_expression","type_edit","\"regexp\"", "Out position","type_edit","position",
	"Out length","type_edit","len", "Out detail","type_edit","detail");
	generator_add_function_to_category("regex","re_match");

	generator_add_function("re_get_detail","Get the (sub)match position and length from the detail.\n"&
	"Typically used after re_search() or re_match()\nsubmatch can be 0 for whole match",6,
	"detail","type_edit","detail", "submatch","type_edit","0", "Out nsubs","type_edit","nsubs",
	"Out line","type_edit","line", "Out position","type_edit","position", "Out length","type_edit","len");
	generator_add_function_to_category("regex","re_get_detail");

	generator_add_function("re_get_match","Get the (sub)matched string from the detail.\n"&
	"Typically used after re_search() or re_match()\nsubmatch can be 0 for whole match",4,
	"original_string","type_edit","orig_str", "detail","type_edit","detail",
	"submatch","type_edit","0", "Out match_str","type_edit","match_str");
	generator_add_function_to_category("regex","re_get_match");

	generator_add_function("re_print_detail","Print the re match details to the debug window.\n"&
	"Typically used after re_search() or re_match().",1, "detail","type_edit","detail");
	generator_add_function_to_category("regex","re_print_detail");

}

# internal function to decode detail from DLL

#/**
#* @param detail 
#* @param position
#* @param nbytes
#* @return 
#*/
static function _detail_decode(detail, position, nbytes)
{
	auto v, v_hi;
	v = int(ascii(substr(detail, position, 1))/2);
	if(nbytes == 2)
	{
		v_hi = int(ascii(substr(detail, position+1, 1))/2);
		v += v_hi*256;
	}
	return v;
}

# dump the detail to WinRunner's debug window
# structure of the detail string:

#/**
#* Print the re match details to the debug window.
#* Typically used after re_search() or re_match().
#* @param detail
#*  (1 byte ) size of this detail, ie. number of submatches + 1
#*  (2 bytes) line number where match occurred, counting from 1
#* [(2 bytes) position of (sub)match, 0-th submatch is whole match
#* [(2 bytes) length of (sub)match
#* [--------- repeated to a maximum of 50 submatches ---]
#* @return 
#*/
public function re_print_detail(detail)
{
	auto size, line, i, pos, len, s;

	size = _detail_decode(detail, 1, 1);
	print "size " & size;
	if (size == 0) return E_OK;
	print "submatches " & (size-1);
	line = _detail_decode(detail, 2, 2);
	print "line " & line;

	for (s=0; s<size; s++)
	{
		pos = _detail_decode(detail, s*4+4, 2);
		len = _detail_decode(detail, s*4+6, 2);
		print "sub(" & s & ") pos: " & pos & " len: " & len;
	}
	return E_OK;
}

# get the (sub)match position and length from the detail

#/**
#* Get the (sub)match position and length from the detail.
#* Typically used after re_search() or re_match()\nsubmatch can be 0 for whole match.
#*
#* @param detail
#* @param submatch
#* @param nsubs
#* @param line
#* @param position
#* @param len
#* @return 
#*/
public function re_get_detail(in detail, in submatch, out nsubs, out line, out position, out len)
{
	auto size;

	nsubs = 0;
	position = 0;
	len = 0;
	line = 0;

	size = _detail_decode(detail, 1, 1);
	if (size == 0) return E_NOT_FOUND;
	nsubs = size-1;
	if (submatch < 0) return E_OUT_OF_RANGE;
	if (submatch+1 > size) return E_OUT_OF_RANGE;

	line = _detail_decode(detail, 2, 2);
	position = _detail_decode(detail, submatch*4+4, 2);
	len = _detail_decode(detail, submatch*4+6, 2);
	return E_OK;
}

# get the (sub)matched string from the detail

#/**
#* Get the (sub)matched string from the detail.
#* Typically used after re_search() or re_match()\nsubmatch can be 0 for whole match.
#* @param orig_str 
#* @param detail 
#* @param submatch
#* @param match_str
#* @return 
#*/
public function re_get_match(in orig_str, in detail, in submatch, out match_str)
{
	auto rc, nsubs, position, len, line;

	match_str = "";

	rc = re_get_detail(detail, submatch, nsubs, line, position, len);
	if (rc != E_OK) return rc;

	match_str = substr(orig_str, position+1, len);
	return E_OK;
}

#------------------------------------------------------