Prepare Nit code for inherited and automatic constructors.
[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 = null
59
60 # The FILE *.
61 attr _file: NativeFile = null
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 = false
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 do end
113 private init without_file do end
114 end
115
116 # File output stream
117 class OFStream
118 special FStream
119 special OStream
120
121 # Write a string.
122 redef meth write(s)
123 do
124 assert _writable
125 write_native(s.to_cstring, s.length)
126 end
127
128 redef meth is_writable do return _writable
129
130 redef meth close
131 do
132 var i = _file.io_close
133 _writable = false
134 end
135
136 # Is the file open in write mode
137 attr _writable: Bool
138
139 # Write `len' bytes from `native'.
140 private meth write_native(native: NativeString, len: Int)
141 do
142 assert _writable
143 var err = _file.io_write(native, len)
144 if err != len then
145 # Big problem
146 printn("Problem in writing : ", err, " ", len, "\n")
147 end
148 end
149
150 # Open the file at `path' for writing.
151 init open(path: String)
152 do
153 _file = io_open_write(path.to_cstring)
154 assert cant_open_file: _file != null
155 _path = path
156 _writable = true
157 end
158
159 private init do end
160 private init without_file do end
161 end
162
163 ###############################################################################
164
165 class Stdin
166 special IFStream
167 private init do
168 _file = native_stdin
169 _path = "/dev/stdin"
170 prepare_buffer(1)
171 end
172 end
173
174 class Stdout
175 special OFStream
176 private init do
177 _file = native_stdout
178 _path = "/dev/stdout"
179 _writable = true
180 end
181 end
182
183 class Stderr
184 special OFStream
185 private init do
186 _file = native_stderr
187 _path = "/dev/stderr"
188 _writable = true
189 end
190 end
191
192 ###############################################################################
193
194 redef class String
195 # return true if a file with this names exists
196 meth file_exists: Bool do return to_cstring.file_exists
197
198 meth file_stat: FileStat do return to_cstring.file_stat
199
200 meth strip_extension(ext: String): String
201 do
202 if has_suffix(ext) then
203 return substring(0, length - ext.length)
204 end
205 return self
206 end
207
208 meth basename(ext: String): String
209 do
210 var pos = last_index_of_from('/', _length - 1)
211 var n = self
212 if pos >= 0 then
213 n = substring_from(pos+1)
214 end
215 return n.strip_extension(ext)
216 end
217
218 meth dirname: String
219 do
220 var pos = last_index_of_from('/', _length - 1)
221 if pos >= 0 then
222 return substring(0, pos)
223 else
224 return "."
225 end
226 end
227
228 meth file_path: String
229 do
230 var l = _length
231 var pos = last_index_of_from('/', l - 1)
232 if pos >= 0 then
233 return substring(0, pos)
234 end
235 return "."
236 end
237
238 # Create a directory (and all intermediate directories if needed)
239 meth mkdir
240 do
241 var dirs = self.split_with("/")
242 var path = new String
243 if dirs.is_empty then return
244 if dirs[0].is_empty then
245 # it was a starting /
246 path.add('/')
247 end
248 for d in dirs do
249 if d.is_empty then continue
250 path.append(d)
251 path.add('/')
252 path.to_cstring.file_mkdir
253 end
254 end
255 end
256
257 redef class NativeString
258 private meth file_exists: Bool is extern "string_NativeString_NativeString_file_exists_0"
259 private meth file_stat: FileStat is extern "string_NativeString_NativeString_file_stat_0"
260 private meth file_mkdir: Bool is extern "string_NativeString_NativeString_file_mkdir_0"
261 end
262
263 universal FileStat
264 special Pointer
265 # This class is system dependent ... must reify the vfs
266 meth mode: Int is extern "file_FileStat_FileStat_mode_0"
267 meth atime: Int is extern "file_FileStat_FileStat_atime_0"
268 meth ctime: Int is extern "file_FileStat_FileStat_ctime_0"
269 meth mtime: Int is extern "file_FileStat_FileStat_mtime_0"
270 meth size: Int is extern "file_FileStat_FileStat_size_0"
271 end
272
273 # Instance of this class are standard FILE * pointers
274 private universal NativeFile
275 special Pointer
276 meth io_read(buf: NativeString, len: Int): Int is extern "file_NativeFile_NativeFile_io_read_2"
277 meth io_write(buf: NativeString, len: Int): Int is extern "file_NativeFile_NativeFile_io_write_2"
278 meth io_close: Int is extern "file_NativeFile_NativeFile_io_close_0"
279 meth file_stat: FileStat is extern "file_NativeFile_NativeFile_file_stat_0"
280 end
281
282 private interface NativeFileCapable
283 meth io_open_read(path: NativeString): NativeFile is extern "file_NativeFileCapable_NativeFileCapable_io_open_read_1"
284 meth io_open_write(path: NativeString): NativeFile is extern "file_NativeFileCapable_NativeFileCapable_io_open_write_1"
285 meth native_stdin: NativeFile is extern "file_NativeFileCapable_NativeFileCapable_native_stdin_0"
286 meth native_stdout: NativeFile is extern "file_NativeFileCapable_NativeFileCapable_native_stdout_0"
287 meth native_stderr: NativeFile is extern "file_NativeFileCapable_NativeFileCapable_native_stderr_0"
288 end
289
290 # Standard input.
291 meth stdin: IFStream do return once new Stdin
292
293 # Standard output.
294 meth stdout: OFStream do return once new Stdout
295
296 # Standard output for error.
297 meth stderr: OFStream do return once new Stderr