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