org.freehep.util.io.ConditionalInputStream Maven / Gradle / Ivy
Show all versions of freehep-io Show documentation
// Copyright 2001-2009, FreeHEP.
package org.freehep.util.io;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* The ConditionalInputStream reads a stream and filters certain parts depending
* of properties and statements in the input.
*
* The following statements, all start with the &at;-sign, are allowed:
*
* - @ifdef property, reads everything up to the next
*
*
if the property is defined.
- @ifndef property, reads
* everything up to the next
*
if the property is not defined.
- @else, corresponding
* else statement
- @endif, corresponging endif statement
*
* The &at;-sign itself must be escaped by a backslash, if used in
* the text followed by any of the keywords described above and no
* action should be taken.
*
* @author Mark Donszelmann
*/
public class ConditionalInputStream extends DecodingInputStream {
private int[] buffer = new int[4096];
private int index;
private int len;
private InputStream in;
private Properties defines;
private int nesting;
private boolean[] ok = new boolean[50];
private boolean escape;
/**
* Creates a Conditional Input Stream from given stream.
*
* @param input
* stream to read from
* @param defines
* set of properties to be used in ifdefs
*/
public ConditionalInputStream(InputStream input, Properties defines) {
super();
in = input;
this.defines = defines;
nesting = 0;
escape = false;
index = 0;
len = 0;
}
@Override
public int read() throws IOException {
int b;
int n;
// read from buffer if possible
if (index < len) {
b = buffer[index];
index++;
} else {
b = in.read();
}
// return if End Of Stream
if (b < 0) {
return -1;
}
// escape \@-signs
if (b == '\\') {
n = in.read();
if (n == '@') {
b = ' ';
escape = true;
}
buffer[0] = n;
index = 0;
len = 1;
}
// check on @ sign
if (b == '@') {
if (escape) {
escape = false;
} else {
// read keyword (ifdef, ifndef, else, endif
index = 0;
StringBuffer s = new StringBuffer();
n = in.read();
while ((n >= 0) && !Character.isWhitespace((char) n)) {
s.append((char) n);
buffer[index] = n;
n = in.read();
index++;
}
buffer[index] = n;
index++;
b = ' ';
// check on keyword
String keyword = s.toString();
if (keyword.equals("ifdef") || keyword.equals("ifndef")) {
// skip whitespace and read property
s = new StringBuffer();
n = in.read();
while ((n >= 0) && Character.isWhitespace((char) n)) {
buffer[index] = n;
n = in.read();
index++;
}
while ((n >= 0) && !Character.isWhitespace((char) n)) {
s.append((char) n);
buffer[index] = n;
n = in.read();
index++;
}
buffer[index] = n;
index++;
// check on property
String property = s.toString();
if (defines.getProperty(property) != null) {
ok[nesting] = (nesting > 0 ? ok[nesting - 1] : true)
&& keyword.equals("ifdef");
} else {
ok[nesting] = (nesting > 0 ? ok[nesting - 1] : true)
&& keyword.equals("ifndef");
}
nesting++;
replaceBufferWithWhitespace(index);
} else if (keyword.equals("else")) {
// FIXME one could have multiple elses without endifs...
// calculate inclusion based on ifdef nesting
if (nesting <= 0) {
throw new RuntimeException(
"@else without corresponding @ifdef");
}
ok[nesting - 1] = (nesting > 1 ? ok[nesting - 2] : true)
&& !ok[nesting - 1];
replaceBufferWithWhitespace(index);
} else if (keyword.equals("endif")) {
// calculate inclusion based on ifdef nesting
if (nesting <= 0) {
throw new RuntimeException(
"@endif without corresponding @ifdef");
}
nesting--;
replaceBufferWithWhitespace(index);
} else {
// not an known @
b = '@';
}
len = index;
index = 0;
}
}
if ((nesting > 0) && !ok[nesting - 1]) {
if (!Character.isWhitespace((char) b)) {
b = ' ';
}
}
return b & 0x00FF;
}
private void replaceBufferWithWhitespace(int size) {
for (int i = 0; i < size; i++) {
if (!Character.isWhitespace((char) buffer[i])) {
buffer[i] = ' ';
}
}
}
}