function ReplaceFunctionOnce
(
	tag,
	func
)
{
	DebugLog(arguments.callee.name + " Start");

	let tagSize = tag.length;

	start = -1;
	end   = -1;

	startArgs = -1;
	endArgs   = -1;

	let scopeLevel = 1;

	args = [];
	arg = "";



	// Find tag.

	while (pos < bufferSize)
	{
		if (FeedComment())
		{
			continue;
		}

		// At this point we know it's not a comment and we are still within bounds.



		// If there is not enough room, feed the remaining buffer and return.

		if ((pos + tagSize) >= bufferSize)
		{
			DebugLog("Not enough room.");

			let size = (bufferSize - pos);

			Feed(size);

			pos += size;

			DebugLog("pos        " + pos);
			DebugLog("bufferSize " + bufferSize);

			return false;
		}



		let name = Substring(buffer, pos, tagSize);
		if (name == tag)
		{
			start = pos;

			break;
		}



		Feed();

		pos++;
	}

	if (start < 0)
	{
		DebugLog("Tag not found. " + tag);

		return false;
	}

	DebugLog("Found tag. " + pos);



	// Verify tag.

	// Back
	if (pos > 0)
	{
		let lastPos = (pos - 1);
		let lastName = buffer.substring(lastPos, (lastPos + 1));

		if (IsFunctionGlyph(lastName))
		{
			DebugLog("Back failed.");

			Feed(tagSize);

			pos += tagSize;

			return false;
		}
	}

	pos += tagSize;



	// Make sure we have at least one character left.

	if (!InRange())
	{
		DebugLog("Out of range.");

		return false;
	}



	// Front
	{
		let name = Substring(buffer, pos, 1);

		if (IsFunctionGlyph(name))
		{
			DebugLog("Front failed.");

			pos = start;

			let size = (tagSize + 1);

			Feed(size);

			pos += size;

			return false;
		}
	}

	// At this point we have a valid tag.



	// Find opening scope.

	while (pos < bufferSize)
	{
		if (SkipComment())
		{
			continue;
		}



		let name = Substring(buffer, pos, 1);
		if (name == "(")
		{
			pos++;

			startArgs = pos;

			break;
		}



		pos++;
	}

	if (startArgs < 0)
	{
		pos = start;

		let lineIndex = GetLineIndex();

		Log(lineIndex + ": Opening scope not found.");

		return true;
	}



	// Find closing scope.

	while (pos < bufferSize)
	{
		if (SkipComment())
		{
			continue;
		}



		let nextPos = (pos + 1);

		let name = Substring(buffer, pos, 1);
		let nextName = "";

		if (nextPos < bufferSize)
		{
			nextName = Substring(buffer, nextPos, 1);
		}

		if (name == "(")
		{
			scopeLevel++;
		}
		else if (name == ")")
		{
			scopeLevel--;
		}

		if (scopeLevel == 0)
		{
			endArgs = pos;

			if (nextName == ";")
			{
				pos += 2;
			}
			else
			{
				pos++;
			}

			end = pos;

			break;
		}



		pos++;
	}

	if (endArgs < 0)
	{
		pos = start;

		let lineIndex = GetLineIndex();

		Log(lineIndex + ": Closing scope not found.");

		return true;
	}

	DebugLog("start " + start);
	DebugLog("end " + end);

	DebugLog("startArgs " + startArgs);
	DebugLog("endArgs " + endArgs);



	// Get args.

	pos = startArgs;

	while (pos < endArgs)
	{
		if (SkipComment())
		{
			continue;
		}



		let name = Substring(buffer, pos, 1);

		if (name == "(")
		{
			scopeLevel++;
		}
		else if (name == ")")
		{
			scopeLevel--;
		}

		if
		(
			(name == ",") &&
			(scopeLevel == 0)
		)
		{
			args.push(arg);

			arg = "";

			pos++;

			continue;
		}

		arg += name;



		pos++;
	}

	if (arg != "")
	{
		args.push(arg);

		arg = "";
	}



	// Clean args.

	for (let argIndex = 0; argIndex < args.length; argIndex++)
	{
		args[argIndex] = Clean(args[argIndex]);
	}



	// Get tab count.

	pos = start;

	tabCount = GetTabCount();

	DebugLog("tabCount " + tabCount);

	// At this point the stream could already differ from the original buffer.
	// So use the stream's size instead of the buffer's position.

	c = Substring(c, 0, (c.length - tabCount));



	// Do stuff.

	if (func(args))
	{
		return true;
	}



	pos = end;

	tabCount = 0; // @Research: Consider lastTabCount.



	DebugLog(arguments.callee.name + " End");

	return false;
}
// All ReplaceFunction functions return true on error.
All ReplaceFunction functions return true on error.
All ReplaceFunction functions return true on error .
function ReplaceFunctionOnce
(
	tag,
	func
)
{
	DebugLog(arguments.callee.name + " Start");
	let tagSize = tag.length;
	start = -1;
	end   = -1;
	startArgs = -1;
	endArgs   = -1;
	let scopeLevel = 1;
	args = [];
	arg = "";
	while (pos < bufferSize)
	{
		if (FeedComment())
		{
			continue;
		}
		if ((pos + tagSize) >= bufferSize)
		{
			DebugLog("Not enough room.");
			let size = (bufferSize - pos);
			Feed(size);
			pos += size;
			DebugLog("pos        " + pos);
			DebugLog("bufferSize " + bufferSize);
			return false;
		}
		let name = Substring(buffer, pos, tagSize);
		if (name == tag)
		{
			start = pos;
			break;
		}
		Feed();
		pos++;
	}
	if (start < 0)
	{
		DebugLog("Tag not found. " + tag);
		return false;
	}
	DebugLog("Found tag. " + pos);
	if (pos > 0)
	{
		let lastPos = (pos - 1);
		let lastName = buffer.substring(lastPos, (lastPos + 1));
		if (IsFunctionGlyph(lastName))
		{
			DebugLog("Back failed.");
			Feed(tagSize);
			pos += tagSize;
			return false;
		}
	}
	pos += tagSize;
	if (!InRange())
	{
		DebugLog("Out of range.");
		return false;
	}
	{
		let name = Substring(buffer, pos, 1);
		if (IsFunctionGlyph(name))
		{
			DebugLog("Front failed.");
			pos = start;
			let size = (tagSize + 1);
			Feed(size);
			pos += size;
			return false;
		}
	}
	while (pos < bufferSize)
	{
		if (SkipComment())
		{
			continue;
		}
		let name = Substring(buffer, pos, 1);
		if (name == "(")
		{
			pos++;
			startArgs = pos;
			break;
		}
		pos++;
	}
	if (startArgs < 0)
	{
		pos = start;
		let lineIndex = GetLineIndex();
		Log(lineIndex + ": Opening scope not found.");
		return true;
	}
	while (pos < bufferSize)
	{
		if (SkipComment())
		{
			continue;
		}
		let nextPos = (pos + 1);
		let name = Substring(buffer, pos, 1);
		let nextName = "";
		if (nextPos < bufferSize)
		{
			nextName = Substring(buffer, nextPos, 1);
		}
		if (name == "(")
		{
			scopeLevel++;
		}
		else if (name == ")")
		{
			scopeLevel--;
		}
		if (scopeLevel == 0)
		{
			endArgs = pos;
			if (nextName == ";")
			{
				pos += 2;
			}
			else
			{
				pos++;
			}
			end = pos;
			break;
		}
		pos++;
	}
	if (endArgs < 0)
	{
		pos = start;
		let lineIndex = GetLineIndex();
		Log(lineIndex + ": Closing scope not found.");
		return true;
	}
	DebugLog("start " + start);
	DebugLog("end " + end);
	DebugLog("startArgs " + startArgs);
	DebugLog("endArgs " + endArgs);
	pos = startArgs;
	while (pos < endArgs)
	{
		if (SkipComment())
		{
			continue;
		}
		let name = Substring(buffer, pos, 1);
		if (name == "(")
		{
			scopeLevel++;
		}
		else if (name == ")")
		{
			scopeLevel--;
		}
		if
		(
			(name == ",") &&
			(scopeLevel == 0)
		)
		{
			args.push(arg);
			arg = "";
			pos++;
			continue;
		}
		arg += name;
		pos++;
	}
	if (arg != "")
	{
		args.push(arg);
		arg = "";
	}
	for (let argIndex = 0; argIndex < args.length; argIndex++)
	{
		args[argIndex] = Clean(args[argIndex]);
	}
	pos = start;
	tabCount = GetTabCount();
	DebugLog("tabCount " + tabCount);
	c = Substring(c, 0, (c.length - tabCount));
	if (func(args))
	{
		return true;
	}
	pos = end;
	tabCount = 0; 
	DebugLog(arguments.callee.name + " End");
	return false;
}
function ReplaceFunctionOnce ( tag , func ) { DebugLog ( arguments . callee . name + " Start" ) ; let tagSize = tag . length ; start = - 1 ; end = - 1 ; startArgs = - 1 ; endArgs = - 1 ; let scopeLevel = 1 ; args = [ ] ; arg = "" ; while ( pos < bufferSize ) { if ( FeedComment ( ) ) { continue ; } if ( ( pos + tagSize ) >= bufferSize ) { DebugLog ( "Not enough room." ) ; let size = ( bufferSize - pos ) ; Feed ( size ) ; pos += size ; DebugLog ( "pos        " + pos ) ; DebugLog ( "bufferSize " + bufferSize ) ; return false ; } let name = Substring ( buffer , pos , tagSize ) ; if ( name == tag ) { start = pos ; break ; } Feed ( ) ; pos ++ ; } if ( start < 0 ) { DebugLog ( "Tag not found. " + tag ) ; return false ; } DebugLog ( "Found tag. " + pos ) ; if ( pos > 0 ) { let lastPos = ( pos - 1 ) ; let lastName = buffer . substring ( lastPos , ( lastPos + 1 ) ) ; if ( IsFunctionGlyph ( lastName ) ) { DebugLog ( "Back failed." ) ; Feed ( tagSize ) ; pos += tagSize ; return false ; } } pos += tagSize ; if ( ! InRange ( ) ) { DebugLog ( "Out of range." ) ; return false ; } { let name = Substring ( buffer , pos , 1 ) ; if ( IsFunctionGlyph ( name ) ) { DebugLog ( "Front failed." ) ; pos = start ; let size = ( tagSize + 1 ) ; Feed ( size ) ; pos += size ; return false ; } } while ( pos < bufferSize ) { if ( SkipComment ( ) ) { continue ; } let name = Substring ( buffer , pos , 1 ) ; if ( name == "(" ) { pos ++ ; startArgs = pos ; break ; } pos ++ ; } if ( startArgs < 0 ) { pos = start ; let lineIndex = GetLineIndex ( ) ; Log ( lineIndex + ": Opening scope not found." ) ; return true ; } while ( pos < bufferSize ) { if ( SkipComment ( ) ) { continue ; } let nextPos = ( pos + 1 ) ; let name = Substring ( buffer , pos , 1 ) ; let nextName = "" ; if ( nextPos < bufferSize ) { nextName = Substring ( buffer , nextPos , 1 ) ; } if ( name == "(" ) { scopeLevel ++ ; } else if ( name == ")" ) { scopeLevel -- ; } if ( scopeLevel == 0 ) { endArgs = pos ; if ( nextName == ";" ) { pos += 2 ; } else { pos ++ ; } end = pos ; break ; } pos ++ ; } if ( endArgs < 0 ) { pos = start ; let lineIndex = GetLineIndex ( ) ; Log ( lineIndex + ": Closing scope not found." ) ; return true ; } DebugLog ( "start " + start ) ; DebugLog ( "end " + end ) ; DebugLog ( "startArgs " + startArgs ) ; DebugLog ( "endArgs " + endArgs ) ; pos = startArgs ; while ( pos < endArgs ) { if ( SkipComment ( ) ) { continue ; } let name = Substring ( buffer , pos , 1 ) ; if ( name == "(" ) { scopeLevel ++ ; } else if ( name == ")" ) { scopeLevel -- ; } if ( ( name == "," ) && ( scopeLevel == 0 ) ) { args . push ( arg ) ; arg = "" ; pos ++ ; continue ; } arg += name ; pos ++ ; } if ( arg != "" ) { args . push ( arg ) ; arg = "" ; } for ( let argIndex = 0 ; argIndex < args . length ; argIndex ++ ) { args [ argIndex ] = Clean ( args [ argIndex ] ) ; } pos = start ; tabCount = GetTabCount ( ) ; DebugLog ( "tabCount " + tabCount ) ; c = Substring ( c , 0 , ( c . length - tabCount ) ) ; if ( func ( args ) ) { return true ; } pos = end ; tabCount = 0 ; DebugLog ( arguments . callee . name + " End" ) ; return false ; }
All ReplaceFunction functions return true on error.
All ReplaceFunction functions return true on error .
// Find tag. // At this point we know it's not a comment and we are still within bounds. // If there is not enough room, feed the remaining buffer and return. // Verify tag. // Back // Make sure we have at least one character left. // Front // At this point we have a valid tag. // Find opening scope. // Find closing scope. // Get args. // Clean args. // Get tab count. // At this point the stream could already differ from the original buffer. // So use the stream's size instead of the buffer's position. // Do stuff. // @Research: Consider lastTabCount.