Index: src/uk/me/parabola/imgfmt/app/BufferedImgFileWriter.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/BufferedImgFileWriter.java	(revision 3262)
+++ src/uk/me/parabola/imgfmt/app/BufferedImgFileWriter.java	(working copy)
@@ -195,8 +195,8 @@
 				// Previous message was confusing people, although it is difficult to come
 				// up with something that is strictly true in all situations.
 				throw new MapFailedException(
-						"There is not enough room in a single garmin map for all the input data\n" +
-								"   The .osm file should be split into smaller pieces first.");
+						"There is not enough room in a single garmin map for all the input data." +
+								" The .osm file should be split into smaller pieces first.");
 			}
 			ByteBuffer newb = ByteBuffer.allocate(bufferSize);
 			newb.order(ByteOrder.LITTLE_ENDIAN);
Index: src/uk/me/parabola/imgfmt/MapFailedException.java
===================================================================
--- src/uk/me/parabola/imgfmt/MapFailedException.java	(revision 3262)
+++ src/uk/me/parabola/imgfmt/MapFailedException.java	(working copy)
@@ -12,6 +12,8 @@
  */
 package uk.me.parabola.imgfmt;
 
+import uk.me.parabola.log.Logger;
+
 /**
  * Used for cases where the current map has failed to compile, but the error
  * is expected to be specific to the map (eg it is too big etc).  When this
@@ -24,8 +26,8 @@
  * @author Steve Ratcliffe
  */
 public class MapFailedException extends RuntimeException {
+	private static final Logger log = Logger.getLogger(MapFailedException.class);
 
-
 	/**
 	 * Constructs a new runtime exception with the specified detail message.
 	 * The cause is not initialized, and may subsequently be initialized by a
@@ -36,6 +38,7 @@
 	 */
 	public MapFailedException(String message) {
 		super(message);
+		log(message);
 	}
 
 	/**
@@ -54,5 +57,17 @@
 	 */
 	public MapFailedException(String message, Throwable cause) {
 		super(message, cause);
+		log(message);
 	}
+	
+	private static void log(String message){
+		String thrownBy = "";
+		try{
+			StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
+			int callerPosInStack = 3; 
+			String[] caller = stackTraceElements[callerPosInStack].getClassName().split("\\.");
+			thrownBy = "(thrown in " + caller[caller.length-1]+ "." +stackTraceElements[callerPosInStack].getMethodName() + "()) ";
+		} catch(Exception e){}
+		log.error(thrownBy + message);
+	}
 }
\ No newline at end of file
Index: src/uk/me/parabola/mkgmap/main/Main.java
===================================================================
--- src/uk/me/parabola/mkgmap/main/Main.java	(revision 3262)
+++ src/uk/me/parabola/mkgmap/main/Main.java	(working copy)
@@ -91,7 +91,23 @@
 	// used for messages in listStyles and checkStyles
 	private String searchedStyleName;
 
+	private volatile int programRC = 0;
+
 	/**
+	 * Used for unit tests
+	 * @param args
+	 */
+	public static void mainNoSystemExit(String[] args) {
+		Main.mainStart(args);
+	}
+	
+	public static void main(String[] args) {
+		int rc = Main.mainStart(args);
+		if (rc != 0)
+			System.exit(1);
+	}
+	
+	/**
 	 * The main program to make or combine maps.  We now use a two pass process,
 	 * first going through the arguments and make any maps and collect names
 	 * to be used for creating summary files like the TDB and gmapsupp.
@@ -98,7 +114,7 @@
 	 *
 	 * @param args The command line arguments.
 	 */
-	public static void main(String[] args) {
+	private static int mainStart(String[] args) {
 		long start = System.currentTimeMillis();
 		System.out.println("Time started: " + new Date());
 		// We need at least one argument.
@@ -105,11 +121,12 @@
 		if (args.length < 1) {
 			printUsage();
 			printHelp(System.err, getLang(), "options");
-			return;
+			return 0;
 		}
 
 		Main mm = new Main();
 
+		int numExitExceptions = 0;
 		try {
 			// Read the command line arguments and process each filename found.
 			CommandArgsReader commandArgs = new CommandArgsReader(mm);
@@ -116,12 +133,20 @@
 			commandArgs.setValidOptions(getValidOptions(System.err));
 			commandArgs.readArgs(args);
 		} catch (MapFailedException e) {
-			System.err.println(e.getMessage());
+			System.err.println(e.getMessage()); // should not happen
 		} catch (ExitException e) {
+			++numExitExceptions;
 			System.err.println(e.getMessage());
 		}
+		
+		System.out.println("Number of ExitExceptions: " + numExitExceptions);
+		
 		System.out.println("Time finished: " + new Date());
-		System.out.println("Total time taken: " + (System.currentTimeMillis() - start) + "ms"); 
+		System.out.println("Total time taken: " + (System.currentTimeMillis() - start) + "ms");
+		if (numExitExceptions > 0 || mm.getProgramRC() != 0){
+			return 1;
+		}
+		return 0;
 	}
 	
 	private static void printUsage (){
@@ -128,6 +153,14 @@
 		System.err.println("Usage: mkgmap [options...] <file.osm>");
 	}
 
+	private void setProgramRC(int rc){
+		programRC = rc;
+	}
+
+	private int getProgramRC(){
+		return programRC;
+	}
+	
 	/**
 	 * Grab the options help file and print it.
 	 * @param err The output print stream to write to.
@@ -420,7 +453,9 @@
 
 
 		List<FilenameTask> filenames = new ArrayList<FilenameTask>();
-
+		
+		int numMapFailedExceptions = 0;
+		
 		if (threadPool != null) {
 			threadPool.shutdown();
 			while (!futures.isEmpty()) {
@@ -451,7 +486,9 @@
 				} catch (ExitException ee) {
 					throw ee;
 				} catch (MapFailedException mfe) {
-					System.err.println(mfe.getMessage());
+//					System.err.println(mfe.getMessage()); // already printed via log
+					numMapFailedExceptions++;
+					setProgramRC(-1);
 				} catch (Throwable t) {
 					t.printStackTrace();
 					if (!args.getProperties().getProperty("keep-going", false)) {
@@ -460,6 +497,7 @@
 				}
 			}
 		}
+		System.out.println("Number of MapFailedExceptions: " + numMapFailedExceptions);
 
 		if (combiners.isEmpty())
 			return;
@@ -574,7 +612,7 @@
 	 * @param filename The original filename.
 	 * @return The file extension.
 	 */
-	private String extractExtension(String filename) {
+	private static String extractExtension(String filename) {
 		String[] parts = filename.toLowerCase(Locale.ENGLISH).split("\\.");
 		List<String> ignore = Arrays.asList("gz", "bz2", "bz");
 
Index: src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java	(revision 3262)
+++ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java	(working copy)
@@ -790,8 +790,7 @@
                             [END-RESTRICT]
                          */
                         restriction.setValid(false);
-                        log.info("Restrictions composed\n" +
-                                "from 3 roads are not yet supported\n");
+                        log.info("Restrictions composed from 3 or more roads are not yet supported");
                     }
                 } else if (name.equals("TraffRoads")) {
                     String[] traffRoads = value.split(",");
Index: src/uk/me/parabola/mkgmap/reader/polish/RoadHelper.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/polish/RoadHelper.java	(revision 3262)
+++ src/uk/me/parabola/mkgmap/reader/polish/RoadHelper.java	(working copy)
@@ -270,7 +270,7 @@
 			if (f.length > 2)
 				boundary = Integer.parseInt(f[2]) > 0;
 			if (log.isDebugEnabled())
-				log.debug("ind=%d, node=%d, bound=%b\n", index, nodeId, boundary);
+				log.debug("ind=" + index + "node=" + nodeId + "bound=" + boundary);
 		}
 
 		public String toString() {
Index: test/func/files/GmapsuppTest.java
===================================================================
--- test/func/files/GmapsuppTest.java	(revision 3262)
+++ test/func/files/GmapsuppTest.java	(working copy)
@@ -47,7 +47,7 @@
 		File f = new File(GMAPSUPP_IMG);
 		assertFalse("does not pre-exist", f.exists());
 
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--gmapsupp",
 				Args.TEST_RESOURCE_IMG + "63240001.img",
@@ -72,7 +72,7 @@
 	 */
 	@Test
 	public void testMpsFile() throws IOException {
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--gmapsupp",
 				"--family-id=150",
@@ -108,7 +108,7 @@
 	@Test
 	public void testCombiningSupps() throws IOException {
 		TestUtils.registerFile("g1.img", "g2.img");
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--gmapsupp",
 				"--family-id=150",
@@ -122,7 +122,7 @@
 		File f = new File("gmapsupp.img");
 		f.renameTo(new File("g1.img"));
 
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--gmapsupp",
 				"--family-id=152",
@@ -134,7 +134,7 @@
 		});
 		f.renameTo(new File("g2.img"));
 
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--gmapsupp",
 				"g1.img",
@@ -173,7 +173,7 @@
 	 */
 	@Test
 	public void testDifferentFamilies() throws IOException {
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--gmapsupp",
 
@@ -212,7 +212,7 @@
 	 */
 	@Test
 	public void testProductBlocks() throws IOException {
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--gmapsupp",
 
@@ -259,7 +259,7 @@
 	 */
 	@Test
 	public void testProductWithSeveralMaps() throws IOException {
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 						Args.TEST_STYLE_ARG,
 						"--gmapsupp",
 
@@ -279,7 +279,7 @@
 	@Test
 	public void testWithIndex() throws IOException {
 		new File("osmmap_mdr.img").delete();
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--gmapsupp",
 				"--index",
@@ -315,7 +315,7 @@
 	public void testWithTwoIndexes() throws IOException {
 		TestUtils.registerFile("osmmap_mdr.img", "osmmap.img", "osmmap.tbd", "osmmap.mdx");
 
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--gmapsupp",
 				"--index",
@@ -355,7 +355,7 @@
 	public void testTwoFamilyIndex() throws IOException {
 		TestUtils.registerFile("osmmap_mdr.img", "osmmap.img", "osmmap.tbd", "osmmap.mdx");
 
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--gmapsupp",
 				"--index",
@@ -407,7 +407,7 @@
 	public void testImplicitCodePageIndex() throws IOException {
 		TestUtils.registerFile("osmmap_mdr.img", "osmmap.img", "osmmap.tbd", "osmmap.mdx");
 
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--code-page=1256",
 
@@ -414,7 +414,7 @@
 				Args.TEST_RESOURCE_OSM + "uk-test-1.osm.gz",
 		});
 
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--gmapsupp",
 				"--index",
@@ -442,7 +442,7 @@
 	public void testWarningOnMismatchedCodePages() throws IOException {
 		TestUtils.registerFile("osmmap.img");
 
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--route",
 				"--code-page=1256",
Index: test/func/files/TdbTest.java
===================================================================
--- test/func/files/TdbTest.java	(revision 3262)
+++ test/func/files/TdbTest.java	(working copy)
@@ -36,7 +36,7 @@
 	 */
 	@Test
 	public void testBasic() throws IOException {
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--tdbfile",
 				Args.TEST_RESOURCE_OSM + "uk-test-1.osm.gz",
@@ -58,7 +58,7 @@
 	public void testOptions() {
 		int thisMapname = 11112222;
 		TestUtils.registerFile(thisMapname + ".img", thisMapname + ".tdb");
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--tdbfile",
 				"--overview-mapname=" + thisMapname,
Index: test/func/lib/TestUtils.java
===================================================================
--- test/func/lib/TestUtils.java	(revision 3262)
+++ test/func/lib/TestUtils.java	(working copy)
@@ -119,7 +119,7 @@
 		try {
 			System.setOut(out);
 			System.setErr(err);
-			Main.main(args.toArray(new String[args.size()]));
+			Main.mainNoSystemExit(args.toArray(new String[args.size()]));
 		} finally {
 			out.close();
 			err.close();
Index: test/func/route/SimpleRouteTest.java
===================================================================
--- test/func/route/SimpleRouteTest.java	(revision 3262)
+++ test/func/route/SimpleRouteTest.java	(working copy)
@@ -36,7 +36,7 @@
 	 */
 	@Test
 	public void testSize() throws FileNotFoundException {
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--route",
 				Args.TEST_RESOURCE_OSM + "uk-test-1.osm.gz",
Index: test/func/SimpleTest.java
===================================================================
--- test/func/SimpleTest.java	(revision 3262)
+++ test/func/SimpleTest.java	(working copy)
@@ -53,7 +53,7 @@
 	@Test
 	public void testBasic() throws FileNotFoundException {
 
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				"--preserve-element-order",
 				Args.TEST_RESOURCE_OSM + "uk-test-1.osm.gz"
@@ -77,7 +77,7 @@
 
 	@Test
 	public void testNoSuchFile() {
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				"no-such-file-xyz.osm",
 		});
 		assertFalse("no file generated", new File(Args.DEF_MAP_FILENAME).exists());
@@ -85,7 +85,7 @@
 
 	@Test
 	public void testPolish() throws FileNotFoundException {
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				Args.TEST_RESOURCE_MP + "test1.mp"
 		});
Index: test/func/sources/TestSourceTest.java
===================================================================
--- test/func/sources/TestSourceTest.java	(revision 3262)
+++ test/func/sources/TestSourceTest.java	(working copy)
@@ -33,7 +33,7 @@
 	@Test
 	public void testAllElements() {
 		checkNoStdFile();
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				"test-map:all-elements"
 		});
 		checkStdFile();
@@ -44,7 +44,7 @@
 	 */
 	@Test
 	public void testAllPoints() {
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				"test-map:test-points"
 		});
 		checkStdFile();
Index: test/func/StructureTest.java
===================================================================
--- test/func/StructureTest.java	(revision 3262)
+++ test/func/StructureTest.java	(working copy)
@@ -72,7 +72,7 @@
 	public static void init() throws FileNotFoundException {
 		TestUtils.deleteOutputFiles();
 
-		Main.main(new String[]{
+		Main.mainNoSystemExit(new String[]{
 				Args.TEST_STYLE_ARG,
 				Args.TEST_RESOURCE_OSM + "uk-test-1.osm.gz"
 		});
