On 04/09/13 08:13, Steve Brophy wrote:
I tested this, and it fixed the problem of including from the wrong
place. Also I saw no repeat of the other errors reported.

Thanks for testing, that is all good news.

For completeness I am attaching a revised version of the patch which removes all the code from the original way of doing this that is no longer used.

There is also a patch removing base-style from the "noname" style which I could not do before because of this very bug ;)

Prebuilt: http://files.mkgmap.org.uk/download/151/mkgmap.jar

..Steve
Index: resources/styles/noname/points
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- resources/styles/noname/points	(revision )
+++ resources/styles/noname/points	(revision )
@@ -0,0 +1,2 @@
+
+include points from default;
Index: resources/styles/noname/lines
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- resources/styles/noname/lines	(revision 2687)
+++ resources/styles/noname/lines	(revision )
@@ -27,3 +27,4 @@
 	{name '${name} (${ref})' | '${ref}' }
 	[0x7 resolution 22]
 
+include lines from default;
Index: resources/styles/noname/info
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- resources/styles/noname/info	(revision 2687)
+++ resources/styles/noname/info	(revision )
@@ -8,9 +8,6 @@
 
 summary: Special map to highlight roads with no name
 
-# This uses the default style as a base
-base-style: default
-
 description {
 	This style is to help find roads that don't yet have a name in OSM
 	by highlighting those roads.  Roads that have a name or a ref
Index: resources/styles/noname/polygons
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- resources/styles/noname/polygons	(revision )
+++ resources/styles/noname/polygons	(revision )
@@ -0,0 +1,2 @@
+
+include polygons from default;
Index: src/uk/me/parabola/mkgmap/osmstyle/StyleFileLoader.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/StyleFileLoader.java	(revision 2687)
+++ src/uk/me/parabola/mkgmap/osmstyle/StyleFileLoader.java	(revision )
@@ -16,6 +16,7 @@
  */
 package uk.me.parabola.mkgmap.osmstyle;
 
+import java.io.Closeable;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.Reader;
@@ -29,7 +30,7 @@
  *
  * @author Steve Ratcliffe
  */
-public abstract class StyleFileLoader {
+public abstract class StyleFileLoader implements Closeable {
 	private static final Logger log = Logger.getLogger(StyleFileLoader.class);
 
 	/**
Index: src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java	(revision 2687)
+++ src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java	(revision )
@@ -16,11 +16,14 @@
  */
 package uk.me.parabola.mkgmap.osmstyle;
 
+import java.io.File;
 import java.io.FileNotFoundException;
-import java.io.FileReader;
 import java.io.Reader;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+
+import uk.me.parabola.imgfmt.Utils;
 import uk.me.parabola.log.Logger;
 import uk.me.parabola.mkgmap.general.LevelInfo;
 import uk.me.parabola.mkgmap.osmstyle.actions.ActionList;
@@ -58,12 +61,14 @@
 	private final TypeReader typeReader;
 
 	private final RuleSet rules;
-	private TokenScanner scanner;
-	private StyleFileLoader loader;
+	private final boolean performChecks;
+	private final Map<Integer, List<Integer>> overlays;
 
-	public RuleFileReader(FeatureKind kind, LevelInfo[] levels, RuleSet rules) {
+	public RuleFileReader(FeatureKind kind, LevelInfo[] levels, RuleSet rules, boolean performChecks, Map<Integer, List<Integer>> overlays) {
 		this.kind = kind;
 		this.rules = rules;
+		this.performChecks = performChecks;
+		this.overlays = overlays;
 		typeReader = new TypeReader(kind, levels);
 	}
 
@@ -74,27 +79,17 @@
 	 * @throws FileNotFoundException If the given file does not exist.
 	 */
 	public void load(StyleFileLoader loader, String name) throws FileNotFoundException {
-		this.loader = loader;
-		load(loader.open(name), name, false, null);
+		loadFile(loader, name);
+		rules.prepare();
 	}
 
-	
 	/**
-	 * Read a rules file.
-	 * @param loader A file loader.
-	 * @param name The name of the file to open.
-	 * @param performChecks if true, report potential errors 
-	 * @param overlays a map with overlays or null
-	 * @throws FileNotFoundException If the given file does not exist.
+	 * Load a rules file.  This should be used when calling recursively when including
+	 * files.
 	 */
-	public void load(StyleFileLoader loader, String name, boolean performChecks, Map<Integer, List<Integer>> overlays) throws FileNotFoundException {
-		this.loader = loader;
-		load(loader.open(name), name, performChecks, overlays);
-	}
-
-	
-	private void load(Reader r, String name, boolean performChecks, Map<Integer, List<Integer>> overlays) {
-		scanner = new TokenScanner(name, r);
+	private void loadFile(StyleFileLoader loader, String name) throws FileNotFoundException {
+		Reader r = loader.open(name);
+		TokenScanner scanner = new TokenScanner(name, r);
 		scanner.setExtraWordChars("-:.");
 
 		ExpressionReader expressionReader = new ExpressionReader(scanner, kind);
@@ -103,7 +98,7 @@
 		// Read all the rules in the file.
 		scanner.skipSpace();
 		while (!scanner.isEndOfFile()) {
-			if (checkCommand())
+			if (checkCommand(loader, scanner))
 				continue;
 
 			if (scanner.isEndOfFile())
@@ -120,13 +115,12 @@
 			else if (actionList == null)
 				throw new SyntaxException(scanner, "No type definition given");
 
-			saveRule(expr, actionList, type);
+			saveRule(scanner, expr, actionList, type);
 			scanner.skipSpace();
 		}
 
 		rules.addUsedTags(expressionReader.getUsedTags());
 		rules.addUsedTags(actionReader.getUsedTags());
-		rules.prepare();
 	}
 
 	/**
@@ -145,8 +139,11 @@
 	 * Called before reading an expression, must put back any token (apart from whitespace) if there is
 	 * not a command.
 	 * @return true if a command was found. The caller should check again for a command.
+	 * @param currentLoader The current style loader. Any included files are loaded from here, if no other
+	 * style is specified.
+	 * @param scanner The current token scanner.
 	 */
-	private boolean checkCommand() {
+	private boolean checkCommand(StyleFileLoader currentLoader, TokenScanner scanner) {
 		scanner.skipSpace();
 		if (scanner.isEndOfFile())
 			return false;
@@ -162,9 +159,8 @@
 					|| (next.getType() == TokType.SYMBOL && (next.isValue("'") || next.isValue("\""))))
 			{
 				String filename = scanner.nextWord();
-				String displayName = filename;
 
-				StyleFileLoader styleLoader = loader;
+				StyleFileLoader loader = currentLoader;
 				scanner.skipSpace();
 
 				// The include can be followed by an optional 'from' clause. The file is read from the given
@@ -176,11 +172,7 @@
 						throw new SyntaxException(scanner, "No style name after 'from'");
 
 					try {
-						// Note: this style loader is never explicitly closed and so if the style loader opens
-						// a file it will not be explicitly closed either. The only loader where this happens has
-						// a finalise() method that closes its underlying file.
-						styleLoader = StyleFileLoader.createStyleLoader(null, styleName);
-						displayName = String.format("%s/%s", styleName, filename);
+						loader = StyleFileLoader.createStyleLoader(null, styleName);
 					} catch (FileNotFoundException e) {
 						throw new SyntaxException(scanner, "Cannot find style: " + styleName);
 					}
@@ -189,10 +181,13 @@
 				scanner.validateNext(";");
 
 				try {
-					scanner.includeFile(displayName, styleLoader.open(filename));
+					loadFile(loader, filename);
 					return true;
 				} catch (FileNotFoundException e) {
 					throw new SyntaxException(scanner, "Cannot open included file: " + filename);
+				} finally {
+					if (loader != currentLoader)
+						Utils.closeFile(loader);
 				}
 			} else {
 				// Wrong syntax for include statement, so push back token to allow a possible expression to be read
@@ -214,7 +209,7 @@
 	 * in a basket we know that the first term is true so we can drop that
 	 * from the expression.
 	 */
-	private void saveRule(Op op, ActionList actions, GType gt) {
+	private void saveRule(TokenScanner scanner, Op op, ActionList actions, GType gt) {
 		log.info("EXP", op, ", type=", gt);
 
 		//System.out.println("From: " + op);
@@ -222,9 +217,9 @@
 		//System.out.println("TO  : " + op2);
 
 		if (op2 instanceof BinaryOp) {
-			optimiseAndSaveBinaryOp((BinaryOp) op2, actions, gt);
+			optimiseAndSaveBinaryOp(scanner, (BinaryOp) op2, actions, gt);
 		} else {
-			optimiseAndSaveOtherOp(op2, actions, gt);
+			optimiseAndSaveOtherOp(scanner, op2, actions, gt);
  		}
 	}
 
@@ -399,7 +394,7 @@
 		}
 	}
 
-	private void optimiseAndSaveOtherOp(Op op, ActionList actions, GType gt) {
+	private void optimiseAndSaveOtherOp(TokenScanner scanner, Op op, ActionList actions, GType gt) {
 		if (op.isType(EXISTS)) {
 			// The lookup key for the exists operation is 'tag=*'
 			createAndSaveRule(op.getFirst().getKeyValue() + "=*", op, actions, gt);
@@ -411,11 +406,12 @@
 	/**
 	 * Optimise the expression tree, extract the primary key and
 	 * save it as a rule.
+	 * @param scanner The token scanner, used for error message file/line numbers.
 	 * @param op a binary expression
 	 * @param actions list of actions to execute on match
 	 * @param gt the Garmin type of the element
 	 */
-	private void optimiseAndSaveBinaryOp(BinaryOp op, ActionList actions, GType gt) {
+	private void optimiseAndSaveBinaryOp(TokenScanner scanner, BinaryOp op, ActionList actions, GType gt) {
 		Op first = op.getFirst();
 		Op second = op.getSecond();
 
@@ -446,9 +442,9 @@
 			}
 		} else if (op.isType(OR)) {
 			LinkedOp op1 = LinkedOp.create(first, true);
-			saveRule(op1, actions, gt);
+			saveRule(scanner, op1, actions, gt);
 
-			saveRestOfOr(actions, gt, second, op1);
+			saveRestOfOr(scanner, actions, gt, second, op1);
 			return;
 		} else {
 			if (!first.isType(FUNCTION) || !((StyleFunction) first).isIndexable())
@@ -462,23 +458,23 @@
 			AndOp andOp = new AndOp();
 			andOp.setFirst(existsOp);
 			andOp.setSecond(op);
-			optimiseAndSaveBinaryOp(andOp, actions, gt);
+			optimiseAndSaveBinaryOp(scanner, andOp, actions, gt);
 			return;
 		}
 
 		createAndSaveRule(keystring, op, actions, gt);
 	}
 
-	private void saveRestOfOr(ActionList actions, GType gt, Op second, LinkedOp op1) {
+	private void saveRestOfOr(TokenScanner scanner, ActionList actions, GType gt, Op second, LinkedOp op1) {
 		if (second.isType(OR)) {
 			LinkedOp nl = LinkedOp.create(second.getFirst(), false);
 			op1.setLink(nl);
-			saveRule(nl, actions, gt);
-			saveRestOfOr(actions, gt, second.getSecond(), op1);
+			saveRule(scanner, nl, actions, gt);
+			saveRestOfOr(scanner, actions, gt, second.getSecond(), op1);
 		} else {
 			LinkedOp op2 = LinkedOp.create(second, false);
 			op1.setLink(op2);
-			saveRule(op2, actions, gt);
+			saveRule(scanner, op2, actions, gt);
 		}
 	}
 
@@ -495,11 +491,15 @@
 
 	public static void main(String[] args) throws FileNotFoundException {
 		if (args.length > 0) {
-			Reader r = new FileReader(args[0]);
 			RuleSet rs = new RuleSet();
 			RuleFileReader rr = new RuleFileReader(FeatureKind.POLYLINE,
-					LevelInfo.createFromString("0:24 1:20 2:18 3:16 4:14"), rs);
-			rr.load(r, "string", true,null);
+					LevelInfo.createFromString("0:24 1:20 2:18 3:16 4:14"), rs, false,
+					Collections.<Integer, List <Integer>>emptyMap());
+
+			StyleFileLoader loader = new DirectoryFileLoader(
+					new File(args[0]).getAbsoluteFile().getParentFile());
+			rr.load(loader, args[0]);
+
 			System.out.println("Result: " + rs);
 		} else {
 			System.err.println("Usage: RuleFileReader <file>");
Index: test/func/lib/TestUtils.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- test/func/lib/TestUtils.java	(revision 2687)
+++ test/func/lib/TestUtils.java	(revision )
@@ -153,7 +153,7 @@
 	public static RuleSet makeRuleSet(StyleFileLoader loader) {
 		RuleSet rs = new RuleSet();
 		RuleFileReader rr = new RuleFileReader(FeatureKind.POLYLINE, LevelInfo.createFromString("0:24 1:20 2:18 3:16 4:14"),
-				rs);
+				rs, false, null);
 		try {
 			rr.load(loader, "lines");
 		} catch (FileNotFoundException e) {
Index: src/uk/me/parabola/mkgmap/scan/TokenScanner.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/uk/me/parabola/mkgmap/scan/TokenScanner.java	(revision 2687)
+++ src/uk/me/parabola/mkgmap/scan/TokenScanner.java	(revision )
@@ -19,11 +19,8 @@
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.Reader;
-import java.util.Deque;
 import java.util.LinkedList;
 
-import uk.me.parabola.imgfmt.Utils;
-
 /**
  * Read a file in terms of word and symbol tokens.
  *
@@ -33,20 +30,17 @@
 	private static final int NO_PUSHBACK = 0;
 
 	// Reading state
-	private Reader reader;
+	private final Reader reader;
 	private int pushback = NO_PUSHBACK;
 	private boolean isEOF;
 
-	private String fileName;
+	private final String fileName;
 	private int linenumber;
 
-	private LinkedList<Token> tokens = new LinkedList<Token>();
+	private final LinkedList<Token> tokens = new LinkedList<Token>();
 
 	private boolean bol = true;
 
-	// Included file state
-	private final Deque<ScanState> states = new LinkedList<ScanState>();
-
 	// Extra word characters.
 	private String extraWordChars = "";
 	private String commentChar = "#";
@@ -234,41 +228,16 @@
 			return c;
 		}
 
-		do {
-			try {
-				c = reader.read();
-			} catch (IOException e) {
+		try {
+			c = reader.read();
+		} catch (IOException e) {
+			isEOF = true;
-				c = -1;
-			}
+			c = -1;
+		}
 
-			// Finished a file, return to the including file if there was one.
-			if (c == -1)
-				popState();
-		} while (!isEOF && c == -1);
-
 		return c;
 	}
 
-	/**
-	 * Finish the currently included file and return the state to start reading from the parent
-	 * file.
-	 *
-	 * This is called when at the end of the current input file.
-	 * If there are no more parent files then the end of file flag is set.
-	 */
-	private void popState() {
-		// Close the current reader that is finished.
-		Utils.closeFile(reader);
-
-		if (states.isEmpty()) {
-			isEOF = true;
-			return;
-		}
-
-		ScanState state = states.removeFirst();
-		state.copyTo(this);
-	}
-
 	private boolean isSpace(int nextch) {
 		return Character.isWhitespace(nextch) || nextch == '\uFEFF';
 	}
@@ -440,67 +409,5 @@
 			this.commentChar = "";
 		else
 			this.commentChar = commentChar;
-	}
-
-	/**
-	 * Include a new file in the token stream.
-	 *
-	 * Stop reading from the current file and save all the details about the file. Sets up to read from
-	 * the included file.
-	 *
-	 * @param filename The name of the file that is being read. This is only used for messages and so doesn't
-	 * have to be a name that can be directly opened for example.
-	 * @param r The input reader for the file.
-	 */
-	public void includeFile(String filename, Reader r) {
-		ScanState state = new ScanState(this);
-		states.addFirst(state);
-
-		reader = r;
-		pushback = NO_PUSHBACK;
-		isEOF = false;
-		fileName = filename;
-		linenumber = 1;
-		tokens = new LinkedList<Token>();
-		bol = true;
-	}
-
-	/**
-	 * Saved state of scanning and individual file. Used when including files.
-	 */
-	private class ScanState {
-		private final Reader reader;
-		private final int pushback;
-
-		private final String fileName;
-		private final int linenumber;
-
-		private final LinkedList<Token> tokens;
-
-		private final boolean bol;
-
-		/**
-		 * Create this state with the state of the token scanner.
-		 */
-		public ScanState(TokenScanner ts) {
-			reader = ts.reader;
-			pushback = ts.pushback;
-			fileName = ts.fileName;
-			linenumber = ts.linenumber;
-			tokens = ts.tokens;
-			bol = ts.bol;
-		}
-
-		/**
-		 * Copy this state to the given token scanner.
-		 */
-		public void copyTo(TokenScanner ts) {
-			ts.reader = reader;
-			ts.pushback = pushback;
-			ts.fileName = fileName;
-			ts.linenumber = linenumber;
-			ts.tokens = tokens;
-			ts.bol = bol;
-		}
 	}
 }
Index: src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java	(revision 2687)
+++ src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java	(revision )
@@ -290,31 +290,31 @@
 		}
 
 		try {
-			RuleFileReader reader = new RuleFileReader(FeatureKind.RELATION, levels, relations);
-			reader.load(fileLoader, "relations", performChecks, getOverlaidTypeMap());
+			RuleFileReader reader = new RuleFileReader(FeatureKind.RELATION, levels, relations, performChecks, getOverlaidTypeMap());
+			reader.load(fileLoader, "relations");
 		} catch (FileNotFoundException e) {
 			// it is ok for this file to not exist.
 			log.debug("no relations file");
 		}
 
 		try {
-			RuleFileReader reader = new RuleFileReader(FeatureKind.POINT, levels, nodes);
-			reader.load(fileLoader, "points", performChecks, getOverlaidTypeMap());
+			RuleFileReader reader = new RuleFileReader(FeatureKind.POINT, levels, nodes, performChecks, getOverlaidTypeMap());
+			reader.load(fileLoader, "points");
 		} catch (FileNotFoundException e) {
 			// it is ok for this file to not exist.
 			log.debug("no points file");
 		}
 
 		try {
-			RuleFileReader reader = new RuleFileReader(FeatureKind.POLYLINE, levels, lines);
-			reader.load(fileLoader, "lines", performChecks, getOverlaidTypeMap());
+			RuleFileReader reader = new RuleFileReader(FeatureKind.POLYLINE, levels, lines, performChecks, getOverlaidTypeMap());
+			reader.load(fileLoader, "lines");
 		} catch (FileNotFoundException e) {
 			log.debug("no lines file");
 		}
 
 		try {
-			RuleFileReader reader = new RuleFileReader(FeatureKind.POLYGON, levels, polygons);
-			reader.load(fileLoader, "polygons", performChecks, getOverlaidTypeMap());
+			RuleFileReader reader = new RuleFileReader(FeatureKind.POLYGON, levels, polygons, performChecks, getOverlaidTypeMap());
+			reader.load(fileLoader, "polygons");
 		} catch (FileNotFoundException e) {
 			log.debug("no polygons file");
 		}
@@ -536,7 +536,7 @@
 			name = "default";
 
 		if (name == null){
-			StyleFileLoader loader;
+			StyleFileLoader loader = null;
 			try {
 				loader = StyleFileLoader.createStyleLoader(loc, null);
 				int numEntries = loader.list().length;
@@ -544,9 +544,12 @@
 					throw new ExitException("Style file " + loc + " contains multiple styles, use option --style to select one.");
 			} catch (FileNotFoundException e) {
 				throw new ExitException("Could not open style file " + loc);
+			} finally {
+				Utils.closeFile(loader);
 			}
 		}
-		Style style = null;
+
+		Style style;
 		try {
 			style = new StyleImpl(loc, name, props, WITHOUT_CHECKS);
 		} catch (SyntaxException e) {
Index: test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java	(revision 2687)
+++ test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java	(revision )
@@ -804,6 +804,21 @@
 	}
 
 	@Test
+	public void testIncludeFrom() {
+		// NOTE: this test uses the default style, which could change.
+		StyleFileLoader loader = new StringStyleFileLoader(new String[][] {
+				{"lines", "include 'lines' from default;\n"},
+		});
+		RuleSet rs = makeRuleSet(loader);
+
+		Way way = new Way(1);
+		way.addTag("highway", "motorway");
+		GType type = getFirstType(rs, way);
+		assertNotNull("Check type not null", type);
+		assertEquals(1, type.getType());
+	}
+
+	@Test
 	public void testLengthFunction() {
 		// Its less than 92m
 		RuleSet rs = makeRuleSet("A=B & length() < 92 [0x5]");
@@ -914,7 +929,8 @@
 
 		RuleSet rs = new RuleSet();
 				RuleFileReader rr = new RuleFileReader(FeatureKind.POINT,
-						LevelInfo.createFromString("0:24 1:20 2:18 3:16 4:14"), rs);
+						LevelInfo.createFromString("0:24 1:20 2:18 3:16 4:14"),
+						rs, false, null);
 		try {
 			rr.load(loader, "points");
 		} catch (FileNotFoundException e) {
_______________________________________________
mkgmap-dev mailing list
[email protected]
http://lists.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to