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