GitHub #262: Variable replacement for offline agent configuration.

For offline agent configuration properties can now contain variables in
${name} format which will be replaced with system properties at runtime.
Based on original PR by user 'debugger'.
diff --git a/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/ConfigLoaderTest.java b/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/ConfigLoaderTest.java
index a704a2b..5cd05c9 100644
--- a/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/ConfigLoaderTest.java
+++ b/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/ConfigLoaderTest.java
@@ -55,4 +55,20 @@
 		assertEquals("testid", config.get("sessionid"));
 	}
 
+	@Test
+	public void testSubstituteProperties() {
+		Properties system = new Properties();
+		system.setProperty("user.home", "/home/jacoco");
+		system.setProperty("java.version", "1.5.0");
+		Properties config = ConfigLoader.load(
+				"/org/jacoco/agent/rt/internal/agent-subst-test.properties",
+				system);
+
+		assertEquals("no$replace}", config.get("key0"));
+		assertEquals("/home/jacoco/coverage/jacoco-1.5.0.exec",
+				config.get("key1"));
+		assertEquals("$/home/jacoco", config.get("key2"));
+		assertEquals("/home/jacoco}}", config.get("key3"));
+		assertEquals("${does.not.exist}", config.get("key4"));
+	}
 }
diff --git a/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/agent-subst-test.properties b/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/agent-subst-test.properties
new file mode 100644
index 0000000..62588a1
--- /dev/null
+++ b/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/agent-subst-test.properties
@@ -0,0 +1,5 @@
+key0=no$replace}
+key1=${user.home}/coverage/jacoco-${java.version}.exec
+key2=$${user.home}
+key3=${user.home}}}
+key4=${does.not.exist}
\ No newline at end of file
diff --git a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/ConfigLoader.java b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/ConfigLoader.java
index f1f2216..4ba9796 100644
--- a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/ConfigLoader.java
+++ b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/ConfigLoader.java
@@ -15,6 +15,8 @@
 import java.io.InputStream;
 import java.util.Map;
 import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * Internal utility to load runtime configuration from a classpath resource and
@@ -26,10 +28,19 @@
 
 	private static final String SYS_PREFIX = "jacoco-agent.";
 
+	private static final Pattern SUBST_PATTERN = Pattern
+			.compile("\\$\\{([^\\}]+)\\}");
+
 	static Properties load(final String resource, final Properties system) {
 		final Properties result = new Properties();
+		loadResource(resource, result);
+		loadSystemProperties(system, result);
+		substSystemProperties(result, system);
+		return result;
+	}
 
-		// 1. Try to load resource
+	private static void loadResource(final String resource,
+			final Properties result) {
 		final InputStream file = Offline.class.getResourceAsStream(resource);
 		if (file != null) {
 			try {
@@ -38,8 +49,10 @@
 				throw new RuntimeException(e);
 			}
 		}
+	}
 
-		// 2. Override with system properties
+	private static void loadSystemProperties(final Properties system,
+			final Properties result) {
 		for (final Map.Entry<Object, Object> entry : system.entrySet()) {
 			final String keystr = entry.getKey().toString();
 			if (keystr.startsWith(SYS_PREFIX)) {
@@ -47,8 +60,24 @@
 						entry.getValue());
 			}
 		}
+	}
 
-		return result;
+	private static void substSystemProperties(final Properties result,
+			final Properties system) {
+		for (final Map.Entry<Object, Object> entry : result.entrySet()) {
+			final String oldValue = (String) entry.getValue();
+			final StringBuilder newValue = new StringBuilder();
+			final Matcher m = SUBST_PATTERN.matcher(oldValue);
+			int pos = 0;
+			while (m.find()) {
+				newValue.append(oldValue.substring(pos, m.start()));
+				final String sub = system.getProperty(m.group(1));
+				newValue.append(sub == null ? m.group(0) : sub);
+				pos = m.end();
+			}
+			newValue.append(oldValue.substring(pos));
+			entry.setValue(newValue.toString());
+		}
 	}
 
 	private ConfigLoader() {
diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index 0a1af5e..4e808f2 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -20,6 +20,13 @@
 
 <h2>Snapshot Build @qualified.bundle.version@ (@build.date@)</h2>
 
+<h3>New Features</h3>
+<ul>
+  <li>For offline instrumemtation agent configuration supports system properties
+      replacements. Implementation based on pull request of GitHub user 'debugger'
+      (GitHub <a href="https://github.com/jacoco/jacoco/issues/262">#226</a>).</li>
+</ul>
+
 <h2>Release 0.7.2 (2014/09/12)</h2>
 
 <h3>Fixed Bugs</h3>
diff --git a/org.jacoco.doc/docroot/doc/offline.html b/org.jacoco.doc/docroot/doc/offline.html
index a6d31b6..9b39038 100644
--- a/org.jacoco.doc/docroot/doc/offline.html
+++ b/org.jacoco.doc/docroot/doc/offline.html
@@ -61,6 +61,16 @@
       "<code>jacoco-agent.destfile</code>".</li>
 </ul>
 
+<p>
+  In both cases configuration values may contain variables in the format
+  <code>${<i>name</i>}</code> which are resolved with system property values
+  at runtime. For example: 
+</p>
+
+<pre class="source">
+destfile=${user.home}/jacoco.exec
+</pre>
+
 <h2>Class Loading and Initialization</h2>
 <p>
   Unlike with on-the-fly instrumentation offline instrumented classes get a