// // Copyright (C) 2010 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.util; import java.io.File; /** * support for specification of source locations * * This maps sourcefile:line1-range strings into instructions that can be efficiently * checked for by listeners. Example formats are: * * X.java (the whole of file X.java) * MyClass.java:42 (file MyClass.java, line1 42) * FooBar.java:42-48 (file FooBar.java, lines 42 to 48) * FooBar.java:42+3 (range of lines from 42 to 45) * x/y/z/whatever:42+ (file with pathname x/y/z/whatever, lines 42 to end) * * * NOTE path names are given in Unix notation, to avoid the usual Java string * quoting problem with backslashes */ public class LocationSpec { public static final int ANYLINE = -1; protected StringMatcher pathSpec; protected StringMatcher fileSpec; protected int fromLine = ANYLINE; // inclusive protected int toLine = ANYLINE; // inclusive /** * factory method that includes the parser */ public static LocationSpec createLocationSpec (String s){ s = s.replace('\\', '/'); String pspec = null, fspec; int line1 = -1, line2 = -1; int idx = s.lastIndexOf(':'); // check if it is just a dreaded "drive letter" if (idx == s.length()-1 || s.charAt(idx + 1) == '/') { idx = -1; } if (idx < 0){ // no line1 spec fspec = s.trim(); } else if (idx > 0){ // line1 spec present fspec = s.substring(0, idx).trim(); // now get the line1 (range) s = s.substring(idx+1).trim(); int len = s.length(); if (len > 0){ int i = 0; for (; i < len; i++) { char c = s.charAt(i); if (c == '-' || c == '+') { line1 = Integer.parseInt(s.substring(0, i)); if (i == len - 1) { // open interval line2 = Integer.MAX_VALUE; } else { line2 = Integer.parseInt(s.substring(i + 1)); if (c == '+') { line2 = line1 + line2; } } break; } } if (i == len) { // single line line1 = Integer.parseInt(s); } } } else { throw new RuntimeException("no filename in LocationSpec: " + s); } idx = fspec.lastIndexOf('/'); if (idx > 0){ pspec = fspec.substring(0, idx); fspec = fspec.substring(idx+1); } else if (idx == 0){ pspec = "/"; fspec = fspec.substring(1); } return new LocationSpec(pspec, fspec, line1, line2); } public LocationSpec (String pspec, String fspec, int line1, int line2){ if (pspec != null){ pathSpec = new StringMatcher(pspec); } fileSpec = new StringMatcher(fspec); fromLine = line1; toLine = line2; } @Override public String toString(){ StringBuilder sb = new StringBuilder(); if (pathSpec != null){ sb.append(pathSpec); sb.append('/'); } sb.append(fileSpec); if (fromLine != ANYLINE){ sb.append(':'); sb.append(fromLine); } if (toLine != ANYLINE){ sb.append('-'); if (toLine != Integer.MAX_VALUE){ sb.append(toLine); } } return sb.toString(); } public boolean matchesFile (File f){ if (fileSpec.matches(f.getName())){ if (pathSpec != null){ String pspec = f.getParent(); pspec = pspec.replace('\\', '/'); // use Unix '/' to avoid quoting issue return pathSpec.matches(pspec); } else { // no path return true; } } return false; } public boolean isAnyLine(){ return fromLine == ANYLINE; } public boolean isLineInterval(){ return toLine != ANYLINE; } public int getLine(){ // for specs that are single locations return fromLine; } public int getFromLine() { return fromLine; } // note - this is < 0 if there was only a public int getToLine() { if (toLine < 0){ if (fromLine >= 0){ return fromLine; } } return toLine; } /** * 'pathName' has to use '/' as separators */ public boolean matchesFile (String pathName){ if (pathName != null){ pathName = pathName.replace('\\', '/'); int idx = pathName.lastIndexOf('/'); if (idx >= 0) { String fname = pathName.substring(idx + 1); if (fileSpec.matches(fname)) { if (pathSpec != null) { String pname = idx > 0 ? pathName.substring(0, idx) : "/"; return pathSpec.matches(pname); } else { return true; } } } else { // no path return fileSpec.matches(pathName); } } return false; } public boolean includesLine (int line){ if (fromLine == ANYLINE){ return true; } else { if (fromLine == line){ return true; } else if (fromLine < line){ if (toLine == ANYLINE){ // single location return false; } else { return (line <= toLine); } } } return false; } }