<cfparam name="attributes.str_Filename" default="" />
<cfparam name="attributes.str_LineDelimiter" default="#chr(13)##chr(10)#" />
<cfparam name="attributes.str_TokenDelimiter" default="#chr(9)#">

<cffunction name="TokenizeLine" returntype="array">
	<cfargument name="str_Content" type="string" required="true" />
	<cfargument name="str_Delimiter" type="string" required="true" />
	
	<cfset var ar_Tokens = arrayNew(1) />
	<cfset var int_CurrPos = 1 />
	<cfset var int_NextPos = 1 />
	<cfset var str_Token = "" />
	
	<cfscript>
		int_NextPos = REFind("#arguments.str_Delimiter#|$", arguments.str_Content, int_CurrPos);
		while (int_NextPos gt 0)
		{
			str_Token = trim(mid(arguments.str_Content, int_CurrPos, int_NextPos - int_CurrPos));
			arrayAppend(ar_Tokens, str_Token);
			int_CurrPos = int_NextPos + len(arguments.str_Delimiter);
			int_NextPos = REFind("#arguments.str_Delimiter#|$", arguments.str_Content, int_CurrPos);
		}
		
		// If the line ends with a token, add
		// an extra empty element to the array
		if (len(arguments.str_Content) gt 0	and mid(arguments.str_Content, len(arguments.str_Content), 1) is arguments.str_Delimiter)
		{
			arrayAppend(ar_Tokens, "");
		}
	</cfscript>
	
	<cfreturn ar_Tokens />
</cffunction>

<cfif ThisTag.ExecutionMode is "Start">
	<!---  Read the file and inititialize position and caller variables.  --->
	<cffile action="read" file="#attributes.str_Filename#" variable="str_Content" />
	<cfset int_CurrPos = 1 />
	<cfset caller.TextParse.str_Line = "" />
	<cfset caller.TextParse.ar_Tokens = arrayNew(1) />
</cfif>

<!---  Find the next delimiter. The regular expression "#attributes.str_LineDelimiter#|$"
	finds the next line delimiter OR the end of the string.  --->
<cfset int_NextPos = REFind("#attributes.str_LineDelimiter#|$", str_Content, int_CurrPos) />

<cfif int_NextPos gt 0>
	<!---  Get and return the line and tokens.  --->
	<cfset str_Line = mid(str_Content, int_CurrPos, int_NextPos - int_CurrPos) />
	<cfset caller.TextParse.str_Line = str_Line />
	<cfset caller.TextParse.ar_Tokens = TokenizeLine(str_Line, attributes.str_TokenDelimiter) />
	
	<!---  Reset the current position.  --->
	<cfset int_CurrPos = int_NextPos + len(attributes.str_LineDelimiter) />
</cfif>

<cfif ThisTag.ExecutionMode is "End">
	<!---  Keep looping as long as we have content to process.  --->
	<cfif int_NextPos gt 0>
		<cfexit method="Loop" />
	</cfif>
</cfif>