001: package persistence.antlr;
002:
003: /* ANTLR Translator Generator
004: * Project led by Terence Parr at http://www.jGuru.com
005: * Software rights: http://www.antlr.org/license.html
006: *
007: * @author Ric Klaren <klaren@cs.utwente.nl>
008: */
009:
010: import java.io.*;
011:
012: /** PreservingFileWriter only overwrites target if the new file is different.
013: Mainly added in order to prevent big and unnecessary recompiles in C++
014: projects.
015: I/O is buffered.
016: */
017: public class PreservingFileWriter extends FileWriter {
018: protected File target_file; /// the file we intend to write to
019: protected File tmp_file; /// the tmp file we create at first
020:
021: public PreservingFileWriter(String file) throws IOException {
022: super (file + ".antlr.tmp");
023:
024: // set up File thingy for target..
025: target_file = new File(file);
026:
027: String parentdirname = target_file.getParent();
028: if (parentdirname != null) {
029: File parentdir = new File(parentdirname);
030:
031: if (!parentdir.exists())
032: throw new IOException("destination directory of '"
033: + file + "' doesn't exist");
034: if (!parentdir.canWrite())
035: throw new IOException("destination directory of '"
036: + file + "' isn't writeable");
037: }
038: if (target_file.exists() && !target_file.canWrite())
039: throw new IOException("cannot write to '" + file + "'");
040:
041: // and for the temp file
042: tmp_file = new File(file + ".antlr.tmp");
043: // have it nuked at exit
044: // RK: this is broken on java 1.4 and
045: // is not compatible with java 1.1 (which is a big problem I'm told :) )
046: // sigh. Any real language would do this in a destructor ;) ;)
047: // tmp_file.deleteOnExit();
048: }
049:
050: /** Close the file and see if the actual target is different
051: * if so the target file is overwritten by the copy. If not we do nothing
052: */
053: public void close() throws IOException {
054: Reader source = null;
055: Writer target = null;
056:
057: try {
058: // close the tmp file so we can access it safely...
059: super .close();
060:
061: char[] buffer = new char[1024];
062: int cnt;
063:
064: // target_file != tmp_file so we have to compare and move it..
065: if (target_file.length() == tmp_file.length()) {
066: // Do expensive read'n'compare
067: Reader tmp;
068: char[] buf2 = new char[1024];
069:
070: source = new BufferedReader(new FileReader(tmp_file));
071: tmp = new BufferedReader(new FileReader(target_file));
072: int cnt1, cnt2;
073: boolean equal = true;
074:
075: while (equal) {
076: cnt1 = source.read(buffer, 0, 1024);
077: cnt2 = tmp.read(buf2, 0, 1024);
078: if (cnt1 != cnt2) {
079: equal = false;
080: break;
081: }
082: if (cnt1 == -1) // EOF
083: break;
084: for (int i = 0; i < cnt1; i++) {
085: if (buffer[i] != buf2[i]) {
086: equal = false;
087: break;
088: }
089: }
090: }
091: // clean up...
092: source.close();
093: tmp.close();
094:
095: source = tmp = null;
096:
097: if (equal)
098: return;
099: }
100:
101: source = new BufferedReader(new FileReader(tmp_file));
102: target = new BufferedWriter(new FileWriter(target_file));
103:
104: while (true) {
105: cnt = source.read(buffer, 0, 1024);
106: if (cnt == -1)
107: break;
108: target.write(buffer, 0, cnt);
109: }
110: } finally {
111: if (source != null) {
112: try {
113: source.close();
114: } catch (IOException e) {
115: ;
116: }
117: }
118: if (target != null) {
119: try {
120: target.close();
121: } catch (IOException e) {
122: ;
123: }
124: }
125: // RK: Now if I'm correct this should be called anytime.
126: if (tmp_file != null && tmp_file.exists()) {
127: tmp_file.delete();
128: tmp_file = null;
129: }
130: }
131: }
132: }
|