################################################################################
# TSL-LIBRARY:	EMOS_STD_string_Lib
################################################################################
# Copyright (C) 2000  EMOS Computer Consulting GmbH
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# For further information please contact:
#
#	Dean Rajovic
#	EMOS Computer Consulting GmbH
#	Oskar-Messter-Straße 25
#	85737 Ismaning
#	Germany
#	tel.: +49 89 608 765-0
#	mailto:drajovic@emos.de
#	http://www.emos.de
################################################################################
# $Revision: 1.2 $
# $Author: drajovic $
# $Date: 2005/01/28 11:18:43 $
# $Archive: /MERCURY/TSL_PROJECTS/EMOS_GPL/STD/emos_std_string_lib/script $
# $NoKeywords: $
################################################################################

#**#
#*	This library contains some useful string manipulation routines.
#*/

#**
#* 	This functions concatenates all elements of the array <arr> into a string.
#*	Elements are separated by <code>sep</code>.
#*<p> NOTE!
#*	Iy the <code>arr</code> is not sequentially inexed (starting from 0), then either the
#*	<code>count</code> should NOT be defined (in operator will be used) or <code>start</code> must
#*	be defined (sequential from then on).
#* @param arr[] (inout)	array to be "streamed"
#* @param sep (in)		(optional) separator,  [default: comma]
#* @param count (in)	(optional) number of elements in the array [default: 0]
#* @param start (in)	(optional) starting index [default: 0]
#* @return
#*	streamed array
#*/

public function arr2str ( inout arr[], in sep, in count, in start )
{
	auto i, end, str = "";
	if ( sep == "" ) sep = ",";
	if ( count == "" )
	{
		count = 0;
		for ( i in arr ) count++;
		for ( i in arr )
			str = str & arr[i] & ((--count) ? sep : ""); 
	}
	else
	{
		end = start*1+count;
		for( i = start*1; i<end; i++ )
			str = str & arr[i] & ((--count) ? sep : "");
	}
	return str;
}

#**
#* 	Replaces all <code>delchr</code> characters with <code>insstr</code> string.
#*<p> NOTE1!
#*	This function internally uses split() to process the string. Unfortunatelly,
#*	split() has an undocumented "feature" that it trims blanks from the given
#*	string before splitting. This has the effect that replace() does the same.
#*	If you don't want the string to be trimmed, use replace1().
#*<p> NOTE2!
#*	The replace() replaces each occurence of individual characters within
#*	<code>delchr</code> with the complete string <code>insstr</code>. It does NOT replace string
#*	<code>delchr</code> with the string <code>insstr</code>.
#* @param str (in)	string to be processed
#* @param delchr (in)	character(s) to be replaced
#* @param insstr (in)	string to be used as replacement
#* @return
#*	converted string
#*/

public function replace ( in str, in delchr, in insstr )
{
	auto count, i, arr[], outstr;
	count = split( str, arr, delchr );
	if ( count == 0 )
		return str;
	outstr = arr[1];
	for( i=2; i <= count; i++ )
		outstr = outstr & insstr & arr[i];
	return outstr;
}

static function test_replace()
{
	auto i, test[], j=0;
	test[j++] = "";
	test[j++] = "x";
	test[j++] = "xxx";
	test[j++] = "xa";
	test[j++] = "ax";
	test[j++] = "axa";
	test[j++] = "xxaxx";
	test[j++] = "axxa";
	test[j++] = "aaa";
	print("");
	for ( i=0; i<j-1; i++ )
		print ( test[i] & "-->" & replace( test[i],"x","|" ) );
	print("");
	for ( i=0; i<j-1; i++ )
		print ( test[i] & "-->" & replace( test[i],"x","" ) );
	print("");
	for ( i=0; i<j-1; i++ )
		print ( test[i] & "-->" & replace( test[i],"xx","||" ) );
}

static const DEFZAP = " ";
#**
#* 	Removes all occuences of <code>zap</code> from the end of <code>str</code> (right trim).
#* @param str (in)	string to be processed
#* @param zap (in)	(optional) string to be removed [default: " "]
#* @return
#*	converted string
#*/

public function strip_trail ( in str, in zap )
{
	auto slen, zlen;
	if ( zap == "" ) 
		zap = DEFZAP;
	slen = length( str );
	zlen = length( zap );
	if ( slen && substr( str, (slen-zlen+1) ) == zap )
		str = strip_trail( substr( str, 1, slen-zlen ) );
	return str;
}

#**
#* 	Removes all occuences of <code>zap</code> from the front of <code>str</code> (left trim).
#* @param str (in)	string to be processed
#* @param zap (in)	(optional) string to be removed [default: " "]
#* @return
#*	converted string
#*/

public function strip_front ( in str, in zap )
{
	auto slen, zlen;
	if ( zap == "" ) 
		zap = DEFZAP;
	slen = length( str );
	zlen = length( zap );
	if ( slen && substr( str, 1, zlen ) == zap )
		str = strip_front( substr( str, 1+zlen ) );
	return str;
}

#**
#* 	Removes all occuences of <code>zap</code> from both sides of <code>str</code> (trim).
#* @param str (in)	string to be processed
#* @param zap (in)	(optional) string to be removed [default: " "]
#* @return
#*	converted string
#*/

public function strip_both ( in str, in zap )
{
	return strip_front( strip_trail ( str, zap ), zap );
}

#**
#* 	Splits a <code>path</code> string into a <code>directory</code> and <code>file</code> parts. The path
#*	separator can be defined with <code>sep</code> (default: backslash) 
#*<p> NOTE!
#*	The function does not analyse whether the <code>file</code> part is indeed a file name.
#*	Anything following the last <sep</code> is treated as <code>file</code>. Anything before is
#*	treated as <code>dir</code>.
# NOTE2!
#	<code>dir</code> does not end with <code>sep</code>.
#* @param path (in)	string to be processed
#* @param dir (out)	directory-part (up until the last <code>sep</code>)
#* @param file (out)	name-part (anything after the last <code>sep</code>)
#* @param sep (in)	(optional) separator (default: backslash)
#* @return
#*	E_OK:	success
#*	!E_OK:	error (do not ust the out variables!)
#*/

public function split_path( in path, out dir, out file, in sep )
{
	auto count, i;
	auto arr[];
	
	if ( sep == "" )
	{
		# assuming backslash is more frequent
		path = replace( path, "/", "\\" );
		sep = "\\";
	}
	
	count = split( path, arr, sep );

	switch ( count )
	{
	case 0:
		return E_BAD_PATH;
	case 1:
		dir = "";
		file = arr[1];
		return E_OK;
	default:
		dir = arr[1];
		for ( i=2; i<count; i++ )
			dir = dir & sep & arr[i];
		file = arr[count];
		return E_OK;
	}
}

#**
#*	Diese Funktion fügt zwei Pfadteile zusammen. Dabei werden <code>sep</code> konvertiert
#*	"/-->\  bzw. \-->/). Standardmeßig werden \ durch / ersetzt.
#*	Eventuell nicht oder merfach vorhandene Separatoren in der Join-Stelle 
#*	werden auf ein <sep> gesetzt.
#*<p> EXAMPLE:
#*<pre>
#*	join_path( "C:\aaa", "bbb.xxx" )   ==>  "C:/aaa/bbb.xxx"
#*	join_path( "C:\aaa\", "\bbb.xxx" ) ==>  "C:/aaa/bbb.xxx"
#*	join_path( "", "bbb.xxx" )         ==>  "/bbb.xxx"
#*	join_path( "C:/aaa" )              ==>  "C:/aaa/"
#*</pre>
#* @param part1 (in)	erster Teil der Pfadangabe
#* @param part2 (in)	zweiter Teil der Pfadangabe
#* @param sep (in)	(optional) Pathseparator to use [default: /]
#* @return
#*	concatenated path
#*/

public function join_path( in part1, in part2, in sep )
{
	auto sep2;
	switch (sep)
	{
	case "":
		sep="/";
		# merke, kein break!
	case "/":
		sep2 = "\\";
		break;
	case "\\":
		sep2 = "/";
		break;
	default:
		sep2 = sep;
	}
	part1 = strip_both( part1, " " );
	part1 = replace( part1, sep2, sep );
	part2 = strip_both( part2, " " );
	part2 = replace( part2, sep2, sep );
	if ( part1 == "" )
		return part2;
	if ( part2 == "" )
		return part1;
	part1 = strip_trail( part1, sep );
	part2 = strip_front( part2, sep );
	return part1 & sep & part2;
}

#===============================================================================
# FUNCTION: trim
#===============================================================================
# DESCRIPTION/PURPOSE:
# 	Diese Funktion entfernt alle Vorkommen Blank vom Ende des <str1>.
# PARAMETERS:
#	in str:		String, das "gestrippt" werden soll
# RETURN VALUE:
#	umgewandelter String
# BEISPIEL:
#	s = "1234  ";
#	x = "<" & trim(s) & ">";	 ==> x = "<1234>"
#===============================================================================

public function trim(in str1)
{
	static i;
	
	for(i=length(str1); i > 0; i--)
		if(substr(str1,i,1) != " ") break;

	return(substr(str1,1,i));
}

#===============================================================================
# FUNCTION: ltrim
#===============================================================================
# DESCRIPTION/PURPOSE:
# 	Diese Funktion entfernt alle Vorkommen Blank vom Anfang des <str1>.
# PARAMETERS:
#	in str:		String, das "gestrippt" werden soll
# RETURN VALUE:
#	umgewandelter String
# BEISPIEL:
#	s = "   1234";
#	x = "<" & ltrim(s) & ">";	 ==> x = "<1234>"
#===============================================================================

public function ltrim(in str1)
{
	static i,j1,j2;
	
	j1 = length(str1);

	for(i=1; i <= j1; i++)
		if(substr(str1,i,1) != " ") break;

	if (i <= j1)
		return(substr(str1,i));
	else
		return(str1);
}

#===============================================================================
# FUNCTION: alltrim
#===============================================================================
# DESCRIPTION/PURPOSE:
# 	Diese Funktion entfernt alle Vorkommen Blank vom Anfang und vom Ende 
#																	des <str1>.
# PARAMETERS:
#	in str:		String, das "gestrippt" werden soll
# RETURN VALUE:
#	umgewandelter String
# BEISPIEL:
#	s = "   1234  ";
#	x = "<" & alltrim(s) & ">";	 ==> x = "<1234>"
#===============================================================================

public function alltrim(in str1)
{
	return(ltrim(trim(str1)));
}

#===============================================================================
# FUNCTION: random_arr  -  Vorbereitung Random-Array.
#===============================================================================
# DESCRIPTION/PURPOSE:
#	Vorbereitung Random-Array.
# PARAMETERS:
#	inout arr[]:	belibige Array 
#	in nnn:			Dimension von Array
# RETURN VALUE:
#	inout arr[]:	Array zufälliger Zahlen 
# BEISPIEL:
#		random_arr(arr1,100);
#		for(i=1; i <= 100; i++)
#			print(arr1[i]);
#===============================================================================

public function random_arr(inout arr1[], in nnn)
{
	static i, ind1;

	for (i = 1; i <= nnn; i++)
		arr1[i] = 0;

	for (i = 1;   i <= nnn;   i++)
	{
		ind1 = int(rand() * nnn) + 1;

		while(  arr1[ind1]  !=  0 )
			ind1 = int(rand() * nnn) + 1;

		arr1[ind1] = i;
	}
}

#===============================================================================
# FUNCTION: replace1
#===============================================================================
# DESCRIPTION/PURPOSE:
# 	Diese Funktion ersetzt alle Vorkommen <s2> durch <s3> in <s1>.
# PARAMETERS:
#	in s1:	String, das "gestrippt" werden soll
#	in s2:	String, das ersetzt werden sollen
#	in s3:	String, das engefügt werden sol
# RETURN VALUE:
#	umgewandelter String
# BEISPIEL:
#	s1 = replace1("1234567890","34","abcd"); ==> s1 = "12abcd567890"
#	s1 = replace1("1234567890","3456","a");  ==> s1 = "12a7890"
#	s1 = replace1("1234567890","3456","");   ==> s1 = "127890"
#===============================================================================

public function replace1(in s1, in s2, in s3)
{
	static i,i1,i2,len2;
	static t1,t2,j1,j2;
	static s1x;

	j1 = 1;
	
	if (s1 == ""  ||  s2 == "")  return(s1);
	
	i1 = index(s1,s2);
	if (i1 == 0)  return(s1);

	s1x  =  s1;   s1 = "";   len2 = length(s2);	

	i2 = index1(s1x,s2);
	
	for(i = 1; i <= i2; i++)
	{
		i1 = index(s1x, s2);

		if (i1 != 1)   s1 = s1  &  substr(s1x, 1, i1-1);

		s1 = s1  &  s3;

		if (i1 + len2 <= length(s1x) )   s1x = substr(s1x, i1 + len2);
		else						     s1x = "";
	}
	return( s1  &  s1x );
}

#===============================================================================
# FUNCTION: substr1
#===============================================================================
# DESCRIPTION/PURPOSE:
# 	Diese Funktion gibt substring aus <str1> vom Anfang <s1> bis zum Ende <s3>
#																	zurück.
# PARAMETERS:
#	in str1:	String, das untersucht werden soll
#	in s2:		String, das den Anfang bestimmt
#	in s3:		String, das das Ende bestimmt
# RETURN VALUE:
#	substring
# BEISPIEL:
#	x = substr1("123<<<abcd>>>45678","<<<",">>>");  ==> x = "abcd"
#	x = substr1("123##abcdef##45678","##","##");	==> x = "abcdef"
#===============================================================================

public function substr1(in str1, in s1, in s2)
{
	static j1,j2,j3,j4,j5;

	j1 = index(str1,s1);
	if (j1 == 0) return("");

	if (s1 == s2)
	{
		j4 = index1(str1,s1);
		if (j4 <= 1) return("");
		
		j4 = index2(str1,s1,1) + length(s1);
		j5 = index2(str1,s1,2) - j4;
		
		return(substr(str1,j4,j5));
	}

	j3 = j1 + length(s1);

	if (s2 == "")	return(substr(str1,j3));
	else
	{
		j2 = index(substr(str1,j3),s2);
		if (j2 == 0) return("");
		return(substr(str1,j3,j2-1));
	}
}

#===============================================================================
# FUNCTION: index1
#===============================================================================
# DESCRIPTION/PURPOSE:
# 	Diese Funktion gibt den Anzahl alle Vorkommen <s2> in <s1> zurück.
# PARAMETERS:
#	in s1:	String, das untersucht werden soll
#	in s2:	subtring, das    sucht werden soll
# RETURN VALUE:
#	Zahl
# BEISPIEL:
#	rc = index1("123ab4567ab890","ab");  ==>  rc = 2
#	rc = index1("123ab4567ababa","ab");  ==>  rc = 3
#===============================================================================

public function index1(in s1, in s2)
{
	static i,i1,i2;

	i=1; i1=0; i2=0;

	while(1)
	{
		i1 = index(substr(s1,i),s2);
		if (i1 == 0) return(i2);
		i2++;
		i  = i + i1 - 1 + length(s2);
	}	
}

#===============================================================================
# FUNCTION: index2
#===============================================================================
# DESCRIPTION/PURPOSE:
# 	Diese Funktion gibt die Position des Vorkommens <s2> in <s1> 
#													mit Nummer <n1> zurück.
# PARAMETERS:
#	in s1:	String, das untersucht werden soll
#	in s2:	subtring, das    sucht werden soll
#	in n1:	Zahl - Nummer des Vorkommens
# RETURN VALUE:
#	Anzahl
# BEISPIEL:
#	Pos:  123456789012345678 				
#	s1 = "12ab345ab6ab789ab0";
#	N = index2(s1,"ab",1);				  ==>  N = 3
#	N = index2(s1,"ab",2);				  ==>  N = 8
#	Letztes Vorkommen:
#	N = index2(s1,"ab",index1(s1,"ab"));  ==>  N = 16
#===============================================================================

public function index2(in s1, in s2, in n1)
{
	static i,i1,i2;

	i=1; i1=0; i2=0;
	
	if (s1 == ""  ||  s2 == ""  ||  n1 == ""  ||  n1 == 0) return(0);

	while(1)
	{
		i1 = index(substr(s1, i),s2);
		if (i1 == 0) return(0);
		if (++i2 == n1) return(i + i1 - 1);
		i  = i + i1 - 1 + length(s2);
	}
}

#===============================================================================
# FUNCTION: split1
#===============================================================================
# DESCRIPTION/PURPOSE:
# 	Änlich wie builtin-Funktion split() außer: statt Field_separators
#																 ganzes String.  
# PARAMETERS:
# 	Änlich wie builtin-Funktion split()
# RETURN VALUE:
# 	Änlich wie builtin-Funktion split()
# BEISPIEL:
#	rc = split1("123##45##6789##0",arr1,"##");  ==> rc = 4 
#												==> arr1[1] = "123" 
#												==> arr1[2] = "45" 
#												==> arr1[3] = "6789" 
#												==> arr1[4] = "0" 
#===============================================================================

public function split1(in s1, inout arr1[], in s2)
{
	static i,i1,len2;

	for(i in arr1)	arr1[i]= "";

	if (index(s1,s2) == 0) return(0);
	
	len2 = length(s2);	
	
	if (substr(s1,1,len2) != s2)	s1 = s2 & s1;
		
	i1 = index1(s1,s2);

	if (substr(s1,length(s1) - len2 + 1, len2) != s2)	s1 = s1 & s2;
	else i1--;

	for (i=1; i <= i1; i++)
		arr1[i]= substr1(substr(s1,index2(s1,s2,i)),s2,s2);

	return(i1);
}

#/**
#* Converts the integer returned by the get_time function to a string formatted as YYYYMMDD.
#* This function converts the integer argument (time) returned by the get_time function to a string,
#* in the format "YYYYMMDD" For example, the string "19981205", is the return value of the function.
#* @param time (in) [optional] integer returned by get_time() or any other integer that is interpreted
#* as number of seconds passes since 1.Jan.1970. [default: today]
#* @return string formatted to YYYYMMDD or empty string if date could not be interpreted.
#*/

public function yyyymmdd_str( in time )
{
	auto t = (time=="" ? time_str() : time_str( time ));
	auto arr[];
	auto count;
	auto mm;
	
	count = split( t, arr, " " );
	if ( count != 5 )
		return "";
	switch ( arr[2] )
	{
	case "Jan": mm = 1; break;
	case "Feb": mm = 2; break;
	case "Mar": mm = 3; break;
	case "Apr": mm = 4; break;
	case "May": mm = 5; break;
	case "Jun": mm = 6; break;
	case "Jul": mm = 7; break;
	case "Aug": mm = 8; break;
	case "Sep": mm = 9; break;
	case "Oct": mm = 10; break;
	case "Nov": mm = 11; break;
	case "Dec": mm = 12; break;
	default: return "";
	}
	return sprintf("%04d%02d%02d", arr[5], mm, arr[3] );
}

###########################################################################
# TSL-LIBRARY:	EMOS_STD_string_Lib
###########################################################################