fix nasty bug in numerical comparison in Interpreter
[org.ibex.js.git] / src / org / ibex / js / Directory.java
1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the Apache Public Source License 2.0 ("the License").
3 // You may not use this file except in compliance with the License.
4
5 package org.ibex.js; 
6
7 import org.ibex.util.*; 
8 import org.ibex.io.*;
9 import java.io.*;
10
11 // FEATURE: support for move
12 // FEATURE: support for bytestreams
13 // FEATURE: cache directories so we can do equality checking on them?
14 // FEATURE: autoconvert "true" to true and "0.3" to 0.3 on readback
15
16 /** 
17  * A crude mechanism for using a filesystem as object storage.
18  *
19  *  This object represents a directory; writing a string, number, or
20  *  boolean to any of its properties will create a file with the
21  *  (encoded) property name as its filename and the "stringified"
22  *  value as its contents.
23  *
24  *  Writing 'null' to one of this object's properties will
25  *  [recursively if necessary] delete the corresponding directory
26  *  entry.
27  *  
28  *  Writing any other object to one of this object's properties will
29  *  create a new Directory object and copy the other object's keys()
30  *  into the new Directory.  This means that assigning one directory
31  *  to a property of another directory will <i>copy</i> the directory,
32  *  not move it.  There is currently no way to move directories.
33  *
34  *  If an object is written to a property that already has an entry,
35  *  the old one is deleted (equivalent to writing 'null') first.
36  * 
37  *  WARNING: when instantiating a Directory object with a file
38  *  argument that points to a non-directory File, this class will
39  *  delete that file and create a directory!
40  */
41 public class Directory extends JS.Immutable {
42
43     File f;
44
45     /** 
46      *  Create the directory object.  Existing directories will be
47      *  preserved; if a file is present it will be obliterated.
48      */ 
49
50     public Directory(File f) throws IOException {
51         this.f = f;
52         if (!f.exists()) new Directory(new File(f.getParent()));
53         if (!f.isDirectory()) destroy(f);
54         f.mkdirs();
55     }
56
57     private static void destroy(File f) throws IOException {
58         if (!f.exists()) return;
59         if (f.isDirectory()) {
60             String[] entries = f.list();
61             for(int i=0; i<entries.length; i++) destroy(new File(f.getAbsolutePath() + File.separatorChar + entries[i]));
62         }
63         f.delete();
64     }
65
66     public void put(JS key0, JS val) throws JSExn {
67         try {
68             if (key0 == null) return;
69             String key = JSU.toString(key0);
70             File f2 = new File(f.getAbsolutePath() + File.separatorChar + Encode.toFilename(key));
71             destroy(f2);
72             if (val == null) return;
73             if (val instanceof org.ibex.io.Fountain) {
74                 Stream stream = ((org.ibex.io.Fountain)val).getStream();
75                 Stream out = new Stream(null, new FileOutputStream(f2));
76                 stream.transcribe(out);
77                 out.close();
78             } else if (val instanceof JSPrimitive) {
79                 OutputStream out = new FileOutputStream(f2);
80                 Writer w = new OutputStreamWriter(out);
81                 w.write(JSU.toString(val));
82                 w.flush();
83                 out.close();
84             } else {
85                 Directory d2 = new Directory(f2);
86                 JS.Enumeration e = val.keys();
87                 while(e.hasNext()) {
88                     JS k = e.next();
89                     JS v = val.get(k);
90                     d2.put(k, v);
91                 }
92             }
93         } catch (IOException ioe) {
94             throw new JSExn.IO(ioe);
95         }
96     }
97
98     public JS get(JS key0) throws JSExn {
99         try {
100             if (key0 == null) return null;
101             String key = JSU.toString(key0);
102             File f2 = new File(f.getAbsolutePath() + File.separatorChar + Encode.toFilename(key));
103             if (!f2.exists()) return null;
104             if (f2.isDirectory()) return new Directory(f2);
105             char[] chars = new char[((int)f2.length()) * 4 + 10];
106             int numchars = 0;
107             Reader r = new InputStreamReader(new FileInputStream(f2));
108             while(true) {
109                 int numread = r.read(chars, numchars, chars.length - numchars);
110                 if (numread == -1) return JSU.S(new String(chars, 0, numchars));
111                 numchars += numread;
112             }
113         } catch (IOException ioe) {
114             throw new JSExn.IO(ioe);
115         }
116     }
117
118     public JS.Enumeration keys() {
119         final String[] elements = f.list();
120         return new JS.Enumeration(null) {
121                 int i = 0;
122                 public boolean _hasNext() { return i < elements.length; }
123                 public JS _next() { return JSU.S(Encode.fromFilename(elements[i++])); }
124             };
125     }
126 }