001package org.cpsolver.ifs.util; 002 003import java.io.BufferedReader; 004import java.io.FileReader; 005import java.io.IOException; 006import java.io.InputStreamReader; 007import java.io.PrintWriter; 008import java.io.Reader; 009import java.util.ArrayList; 010import java.util.Iterator; 011import java.util.List; 012 013/** 014 * A class for reading prolog files. 015 * 016 * @author Tomáš Müller 017 * @version IFS 1.3 (Iterative Forward Search)<br> 018 * Copyright (C) 2006 - 2014 Tomáš Müller<br> 019 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 020 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 021 * <br> 022 * This library is free software; you can redistribute it and/or modify 023 * it under the terms of the GNU Lesser General Public License as 024 * published by the Free Software Foundation; either version 3 of the 025 * License, or (at your option) any later version. <br> 026 * <br> 027 * This library is distributed in the hope that it will be useful, but 028 * WITHOUT ANY WARRANTY; without even the implied warranty of 029 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 030 * Lesser General Public License for more details. <br> 031 * <br> 032 * You should have received a copy of the GNU Lesser General Public 033 * License along with this library; if not see 034 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 035 */ 036public class PrologFile implements Iterator<PrologFile.Term> { 037 private BufferedReader iBufferedReader = null; 038 private Term iNextTerm = null; 039 040 public PrologFile(String file) throws java.io.IOException { 041 iBufferedReader = new BufferedReader(new FileReader(file)); 042 iNextTerm = (iBufferedReader.ready() ? readTerm(new SpecialReader(iBufferedReader)) : null); 043 if (iNextTerm == null) 044 iBufferedReader.close(); 045 else 046 iBufferedReader.readLine(); 047 } 048 049 /** Reads a prolog file. It returns a set of terms 050 * @param is input stream 051 * @param term term to read 052 * @return list of terms 053 * @throws java.io.IOException an exception 054 **/ 055 public static List<Term> readTermsFromStream(java.io.InputStream is, String term) throws java.io.IOException { 056 BufferedReader br = new BufferedReader(new InputStreamReader(is)); 057 List<Term> ret = new ArrayList<Term>(); 058 // int x=0; 059 while (br.ready()) { 060 Term t = readTerm(new SpecialReader(br)); 061 // System.out.println(t); 062 // x++; 063 // if (x>10) break; 064 if (t != null && t.getText() != null && t.getText().startsWith(term)) { 065 ret.add(t); 066 } 067 br.readLine(); 068 } 069 br.close(); 070 return ret; 071 } 072 073 /** Writes a set of terms. 074 * @param pw print writer 075 * @param terms list of terms to write 076 * @throws java.io.IOException an exception 077 **/ 078 public static void writeTerms(PrintWriter pw, List<Term> terms) throws java.io.IOException { 079 for (Term t : terms) { 080 writeTerm(pw, t); 081 } 082 } 083 084 /** reads a term */ 085 private static Term readTerm(SpecialReader is) throws IOException { 086 StringBuffer text = new StringBuffer(); 087 List<Term> content = null; 088 int i; 089 if ((i = is.read()) >= 0) { 090 while ((char) i == '%' || (char) i == ':') { 091 do { 092 i = is.read(); 093 } while (i >= 0 && !(i == 0x0d || i == 0x0a)); 094 i = is.read(); 095 if (i >= 0 && (i == 0x0d || i == 0x0a)) 096 i = is.read(); 097 } 098 if (i >= 0) 099 is.flush((char) i); 100 } 101 char prev = (char) i; 102 if (i >= 0) 103 while ((i = is.read()) >= 0) { 104 char ch = (char) i; 105 if (ch == '\n' || ch == '\r') 106 if (prev == '.') 107 break; 108 else 109 continue; 110 if (ch == '(' || ch == '[') { 111 content = new ArrayList<Term>(); 112 content.add(readTerm(is)); 113 } else if (content == null && (ch == ',' || ch == ')' || ch == ']')) { 114 is.flush(ch); 115 break; 116 } else if (ch == ',') 117 content.add(readTerm(is)); 118 else if (ch == ')' || ch == ']') 119 break; 120 else 121 text.append(ch); 122 prev = ch; 123 } 124 else 125 return null; 126 Term ret = new Term(text.toString().trim(), content); 127 return ret; 128 } 129 130 /** writes a term */ 131 private static void writeTerm(PrintWriter pw, Term t) { 132 pw.println(t.toString() + "."); 133 } 134 135 @Override 136 public boolean hasNext() { 137 return iNextTerm != null; 138 } 139 140 @Override 141 public Term next() { 142 Term ret = iNextTerm; 143 try { 144 iNextTerm = (iBufferedReader.ready() ? readTerm(new SpecialReader(iBufferedReader)) : null); 145 } catch (java.io.IOException x) { 146 iNextTerm = null; 147 } 148 try { 149 if (iNextTerm == null) 150 iBufferedReader.close(); 151 else 152 iBufferedReader.readLine(); 153 } catch (java.io.IOException x) { 154 } 155 return ret; 156 } 157 158 @Override 159 public void remove() { 160 } 161 162 /** Flushable reader -- extension of java.io.Reader */ 163 private static class SpecialReader { 164 /** reader */ 165 private Reader iReader = null; 166 /** flushed characters */ 167 private StringBuffer iFlushedChars = new StringBuffer(); 168 169 /** constructor 170 * @param r a reader to wrap 171 **/ 172 public SpecialReader(Reader r) { 173 iReader = r; 174 } 175 176 /** reads a byte 177 * @return a byte that was read 178 * @throws java.io.IOException an exception thrown by the parent reader */ 179 public int read() throws java.io.IOException { 180 if (iFlushedChars.length() == 0) 181 return iReader.read(); 182 char ret = iFlushedChars.charAt(0); 183 iFlushedChars.deleteCharAt(0); 184 return ret; 185 } 186 187 /** flush (return to stream) a character 188 * @param ch a character to be returned back 189 **/ 190 public void flush(char ch) { 191 iFlushedChars.insert(0, ch); 192 } 193 } 194 195 /** Term -- it can contain a text and a content (set of terms) */ 196 public static class Term { 197 /** text */ 198 private String iText = null; 199 /** content */ 200 private List<Term> iContent = null; 201 202 @Override 203 public boolean equals(Object o) { 204 if (o == null || !(o instanceof Term)) 205 return false; 206 Term t = (Term) o; 207 if (iText == null && t.iText != null) 208 return false; 209 if (iText != null && t.iText == null) 210 return false; 211 if (iText != null && !iText.equals(t.iText)) 212 return false; 213 if (iContent == null && t.iContent != null) 214 return false; 215 if (iContent != null && t.iContent == null) 216 return false; 217 if (iContent != null && !iContent.equals(t.iContent)) 218 return false; 219 return true; 220 } 221 222 /** constructor 223 * @param text name of the term 224 **/ 225 public Term(String text) { 226 iText = text; 227 iContent = null; 228 } 229 230 /** constructor 231 * @param content inner terms 232 **/ 233 public Term(List<Term> content) { 234 iText = null; 235 iContent = content; 236 } 237 238 /** constructor 239 * @param text name of the term 240 * @param content inner terms 241 **/ 242 public Term(String text, List<Term> content) { 243 iText = text; 244 iContent = content; 245 } 246 247 /** constructor 248 * @param text name of the term 249 * @param content inner terms 250 **/ 251 public Term(String text, Term[] content) { 252 iText = text; 253 if (content == null) { 254 iContent = null; 255 } else { 256 iContent = new ArrayList<Term>(); 257 for (int i = 0; i < content.length; i++) 258 iContent.add(content[i]); 259 } 260 } 261 262 /** constructor 263 * @param content inner terms 264 **/ 265 public Term(Term[] content) { 266 this(null, content); 267 } 268 269 /** return text 270 * @return term name 271 */ 272 public String getText() { 273 return iText; 274 } 275 276 /** return content 277 * @return term content (inner terms) 278 */ 279 public List<Term> getContent() { 280 return iContent; 281 } 282 283 /** content size 284 * @return number of inner terms 285 **/ 286 public int size() { 287 return (iContent == null ? -1 : iContent.size()); 288 } 289 290 /** return text as int 291 * @return term name as int 292 **/ 293 public int toInt() { 294 return Integer.parseInt(iText); 295 } 296 297 /** return text as long 298 * @return term name as long 299 */ 300 public long toLong() { 301 return Long.parseLong(iText); 302 } 303 304 /** return text as double 305 * @return term name as double 306 */ 307 public double toDouble() { 308 return Double.parseDouble(iText); 309 } 310 311 /** return text as boolean 312 * @return term name as boolean 313 */ 314 public boolean toBoolean() { 315 return (toInt() != 0); 316 } 317 318 /** return content as boolean array 319 * @return inner terms as booleans 320 */ 321 public boolean[] toBooleanArray() { 322 if (iContent.size() == 1 && iContent.get(0).toString().length() == 0) 323 return new boolean[] {}; 324 boolean[] ret = new boolean[iContent.size()]; 325 for (int i = 0; i < ret.length; i++) { 326 ret[i] = elementAt(i).toBoolean(); 327 } 328 return ret; 329 } 330 331 /** return content as string array 332 * @return inner terms as strings 333 */ 334 public String[] toStringArray() { 335 if (iContent.size() == 1 && iContent.get(0).toString().length() == 0) 336 return new String[] {}; 337 String[] ret = new String[iContent.size()]; 338 for (int i = 0; i < ret.length; i++) { 339 Term t = elementAt(i); 340 ret[i] = (t.getText().length() > 0 ? t.toString() : t.elementAt(0).toString()); 341 } 342 return ret; 343 } 344 345 /** return content as int array 346 * @return inner terms as ints 347 */ 348 public int[] toIntArray() { 349 // System.err.println("ToIntArray: "+this); 350 if (iContent.size() == 1 && iContent.get(0).toString().length() == 0) 351 return new int[] {}; 352 int[] ret = new int[iContent.size()]; 353 for (int i = 0; i < ret.length; i++) { 354 Term t = elementAt(i); 355 ret[i] = (t.getText().length() > 0 ? Integer.parseInt(t.getText()) : t.elementAt(0).toInt()); 356 // System.err.println(" "+i+" .. "+ret[i]); 357 } 358 return ret; 359 } 360 361 /** idx-th element of content 362 * @param idx index of the inner term 363 * @return inner term 364 */ 365 public Term elementAt(int idx) { 366 try { 367 return iContent.get(idx); 368 } catch (Exception e) { 369 return null; 370 } 371 } 372 373 /** element of content named name 374 * @param name name of the inner term 375 * @return inner term, null if not present 376 **/ 377 public Term element(String name) { 378 try { 379 for (Term t : iContent) { 380 if (t.getText() != null && t.getText().equals(name)) 381 return t; 382 } 383 return null; 384 } catch (Exception e) { 385 return null; 386 } 387 } 388 389 /** index of element of content named name 390 * @param name name of the inner term 391 * @return index of the inner term, -1 if not present 392 */ 393 public int indexOf(String name) { 394 try { 395 int idx = 0; 396 for (Term t : iContent) { 397 if (t.getText() != null && t.getText().equals(name)) 398 return idx; 399 idx++; 400 } 401 return -1; 402 } catch (Exception e) { 403 return -1; 404 } 405 } 406 407 /** string representation of term */ 408 @Override 409 public String toString() { 410 boolean isArray = (iText == null || iText.length() == 0); 411 StringBuffer sb = new StringBuffer(isArray ? "" : iText); 412 if (iContent != null) { 413 sb.append(isArray ? "[" : "("); 414 for (Iterator<Term> e = iContent.iterator(); e.hasNext();) { 415 sb.append(e.next().toString()); 416 sb.append(e.hasNext() ? "," : ""); 417 } 418 sb.append(isArray ? "]" : ")"); 419 } 420 return sb.toString(); 421 } 422 423 @Override 424 public int hashCode() { 425 return toString().hashCode(); 426 } 427 428 @Override 429 public Object clone() { 430 return new Term(iText == null ? null : new String(iText), iContent == null ? iContent 431 : new ArrayList<Term>(iContent)); 432 } 433 } 434}