First NIT release and new clean mercurial repository
[nit.git] / lib / standard / file.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2004-2008 Jean Privat <jean@pryen.org>
4 # Copyright 2008 Floréal Morandat <morandat@lirmm.fr>
5 #
6 # This file is free software, which comes along with NIT. This software is
7 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
9 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
10 # is kept unaltered, and a notification of the changes is added.
11 # You are allowed to redistribute it and sell it, alone or is a part of
12 # another product.
13
14 # This module handle file input and output
15 package file
16
17 intrude import stream
18 intrude import string
19 import string_search
20
21 redef class Object
22 # Simple I/O
23
24 # Print `objects' on the standard output (`stdout').
25 protected meth printn(objects: Object...)
26 do
27 stdout.write(objects.to_s)
28 end
29
30 # Print an `object' on the standard output (`stdout') and add a newline.
31 protected meth print(object: Object)
32 do
33 if object != null then
34 stdout.write(object.to_s)
35 end
36 stdout.write("\n")
37 end
38
39 # Read a character from the standard input (`stdin').
40 protected meth getc: Char
41 do
42 return stdin.read_char.ascii
43 end
44
45 # Read a line from the standard input (`stdin').
46 protected meth gets: String
47 do
48 return stdin.read_line
49 end
50 end
51
52 # File Abstract Stream
53 class FStream
54 special IOS
55 special NativeFileCapable
56
57 # The path of the file.
58 readable attr _path: String
59
60 # The FILE *.
61 attr _file: NativeFile
62
63 meth file_stat: FileStat
64 do return _file.file_stat end
65 end
66
67 # File input stream
68 class IFStream
69 special FStream
70 special BufferedIStream
71 # Misc
72
73 meth reopen
74 do
75 if not eof then close
76 _file = io_open_read(_path.to_cstring)
77 _end_reached = false
78 _buffer_pos = 0
79 _buffer.clear
80 end
81
82 redef meth close
83 do
84 var i = _file.io_close
85 _end_reached = true
86 end
87
88 # Fill the internal read buffer. Needed by read operations.
89 redef meth fill_buffer
90 do
91 var nb = _file.io_read(_buffer._items, _buffer._capacity)
92 if nb <= 0 then
93 _end_reached = true
94 nb = 0
95 end
96 _buffer._length = nb
97 _buffer_pos = 0
98 end
99
100 # End of file?
101 redef readable attr _end_reached: Bool
102
103 # Open the file at `path' for reading.
104 init open(path: String)
105 do
106 _path = path
107 prepare_buffer(10)
108 _file = io_open_read(_path.to_cstring)
109 assert cant_open_file: _file != null
110 end
111
112 private init without_file do end
113 end
114
115 # File output stream
116 class OFStream
117 special FStream
118 special OStream
119
120 # Write a string.
121 redef meth write(s)
122 do
123 assert _writable
124 write_native(s.to_cstring, s.length)
125 end
126
127 redef meth is_writable do return _writable
128
129 redef meth close
130 do
131 var i = _file.io_close
132 _writable = false
133 end
134
135 # Is the file open in write mode
136 attr _writable: Bool
137
138 # Write `len' bytes from `native'.
139 private meth write_native(native: NativeString, len: Int)
140 do
141 assert _writable
142 var err = _file.io_write(native, len)
143 if err != len then
144 # Big problem
145 printn("Problem in writing : ", err, " ", len, "\n")
146 end
147 end
148
149 # Open the file at `path' for writing.
150 init open(path: String)
151 do
152 _file = io_open_write(path.to_cstring)
153 assert cant_open_file: _file != null
154 _path = path
155 _writable = true
156 end
157
158 private init without_file do end
159 end
160
161 ###############################################################################
162
163 class Stdin
164 special IFStream
165 private init do
166 _file = native_stdin
167 _path = "/dev/stdin"
168 prepare_buffer(1)
169 end
170 end
171
172 class Stdout
173 special OFStream
174 private init do
175 _file = native_stdout
176 _path = "/dev/stdout"
177 _writable = true
178 end
179 end
180
181 class Stderr
182 special OFStream
183 private init do
184 _file = native_stderr
185 _path = "/dev/stderr"
186 _writable = true
187 end
188 end
189
190 ###############################################################################
191
192 redef class String
193 # return true if a file with this names exists
194 meth file_exists: Bool do return to_cstring.file_exists
195
196 meth file_stat: FileStat do return to_cstring.file_stat
197
198 meth strip_extension(ext: String): String
199 do
200 if has_suffix(ext) then
201 return substring(0, length - ext.length)
202 end
203 return self
204 end
205
206 meth basename(ext: String): String
207 do
208 var pos = last_index_of_from('/', _length - 1)
209 var n = self
210 if pos >= 0 then
211 n = substring_from(pos+1)
212 end
213 return n.strip_extension(ext)
214 end
215
216 meth dirname: String
217 do
218 var pos = last_index_of_from('/', _length - 1)
219 if pos >= 0 then
220 return substring(0, pos)
221 else
222 return "."
223 end
224 end
225
226 meth file_path: String
227 do
228 var l = _length
229 var pos = last_index_of_from('/', l - 1)
230 if pos >= 0 then
231 return substring(0, pos)
232 end
233 return "."
234 end
235
236 # Create a directory (and all intermediate directories if needed)
237 meth mkdir
238 do
239 var dirs = self.split_with("/")
240 var path = new String
241 if dirs.is_empty then return
242 if dirs[0].is_empty then
243 # it was a starting /
244 path.add('/')
245 end
246 for d in dirs do
247 if d.is_empty then continue
248 path.append(d)
249 path.add('/')
250 path.to_cstring.file_mkdir
251 end
252 end
253 end
254
255 redef class NativeString
256 private meth file_exists: Bool is extern "string_NativeString_NativeString_file_exists_0"
257 private meth file_stat: FileStat is extern "string_NativeString_NativeString_file_stat_0"
258 private meth file_mkdir: Bool is extern "string_NativeString_NativeString_file_mkdir_0"
259 end
260
261 universal FileStat
262 special Pointer
263 # This class is system dependent ... must reify the vfs
264 meth mode: Int is extern "file_FileStat_FileStat_mode_0"
265 meth atime: Int is extern "file_FileStat_FileStat_atime_0"
266 meth ctime: Int is extern "file_FileStat_FileStat_ctime_0"
267 meth mtime: Int is extern "file_FileStat_FileStat_mtime_0"
268 meth size: Int is extern "file_FileStat_FileStat_size_0"
269 end
270
271 # Instance of this class are standard FILE * pointers
272 private universal NativeFile
273 special Pointer
274 meth io_read(buf: NativeString, len: Int): Int is extern "file_NativeFile_NativeFile_io_read_2"
275 meth io_write(buf: NativeString, len: Int): Int is extern "file_NativeFile_NativeFile_io_write_2"
276 meth io_close: Int is extern "file_NativeFile_NativeFile_io_close_0"
277 meth file_stat: FileStat is extern "file_NativeFile_NativeFile_file_stat_0"
278 end
279
280 private class NativeFileCapable
281 meth io_open_read(path: NativeString): NativeFile is extern "file_NativeFileCapable_NativeFileCapable_io_open_read_1"
282 meth io_open_write(path: NativeString): NativeFile is extern "file_NativeFileCapable_NativeFileCapable_io_open_write_1"
283 meth native_stdin: NativeFile is extern "file_NativeFileCapable_NativeFileCapable_native_stdin_0"
284 meth native_stdout: NativeFile is extern "file_NativeFileCapable_NativeFileCapable_native_stdout_0"
285 meth native_stderr: NativeFile is extern "file_NativeFileCapable_NativeFileCapable_native_stderr_0"
286 end
287
288 # Standard input.
289 meth stdin: IFStream do return once new Stdin
290
291 # Standard output.
292 meth stdout: OFStream do return once new Stdout
293
294 # Standard output for error.
295 meth stderr: OFStream do return once new Stderr