Imported Upstream version 1.46.0
[platform/upstream/nghttp2.git] / third-party / mruby / mrbgems / mruby-io / mrblib / io.rb
1 ##
2 # IO
3
4 class IOError < StandardError; end
5 class EOFError < IOError; end
6
7 class IO
8   SEEK_SET = 0
9   SEEK_CUR = 1
10   SEEK_END = 2
11
12   BUF_SIZE = 4096
13
14   def self.open(*args, &block)
15     io = self.new(*args)
16
17     return io unless block
18
19     begin
20       yield io
21     ensure
22       begin
23         io.close unless io.closed?
24       rescue StandardError
25       end
26     end
27   end
28
29   def self.popen(command, mode = 'r', opts={}, &block)
30     if !self.respond_to?(:_popen)
31       raise NotImplementedError, "popen is not supported on this platform"
32     end
33     io = self._popen(command, mode, opts)
34     return io unless block
35
36     begin
37       yield io
38     ensure
39       begin
40         io.close unless io.closed?
41       rescue IOError
42         # nothing
43       end
44     end
45   end
46
47   def self.pipe(&block)
48     if !self.respond_to?(:_pipe)
49       raise NotImplementedError, "pipe is not supported on this platform"
50     end
51     if block
52       begin
53         r, w = IO._pipe
54         yield r, w
55       ensure
56         r.close unless r.closed?
57         w.close unless w.closed?
58       end
59     else
60       IO._pipe
61     end
62   end
63
64   def self.read(path, length=nil, offset=nil, opt=nil)
65     if not opt.nil?        # 4 arguments
66       offset ||= 0
67     elsif not offset.nil?  # 3 arguments
68       if offset.is_a? Hash
69         opt = offset
70         offset = 0
71       else
72         opt = {}
73       end
74     elsif not length.nil?  # 2 arguments
75       if length.is_a? Hash
76         opt = length
77         offset = 0
78         length = nil
79       else
80         offset = 0
81         opt = {}
82       end
83     else                   # only 1 argument
84       opt = {}
85       offset = 0
86       length = nil
87     end
88
89     str = ""
90     fd = -1
91     io = nil
92     begin
93       if path[0] == "|"
94         io = IO.popen(path[1..-1], (opt[:mode] || "r"))
95       else
96         mode = opt[:mode] || "r"
97         fd = IO.sysopen(path, mode)
98         io = IO.open(fd, mode)
99       end
100       io.seek(offset) if offset > 0
101       str = io.read(length)
102     ensure
103       if io
104         io.close
105       elsif fd != -1
106         IO._sysclose(fd)
107       end
108     end
109     str
110   end
111
112   def flush
113     # mruby-io always writes immediately (no output buffer).
114     raise IOError, "closed stream" if self.closed?
115     self
116   end
117
118   def hash
119     # We must define IO#hash here because IO includes Enumerable and
120     # Enumerable#hash will call IO#read...
121     self.__id__
122   end
123
124   def write(string)
125     str = string.is_a?(String) ? string : string.to_s
126     return 0 if str.empty?
127     unless @buf.empty?
128       # reset real pos ignore buf
129       seek(pos, SEEK_SET)
130     end
131     len = syswrite(str)
132     len
133   end
134
135   def <<(str)
136     write(str)
137     self
138   end
139
140   def eof?
141     _check_readable
142     begin
143       _read_buf
144       return @buf.empty?
145     rescue EOFError
146       return true
147     end
148   end
149   alias_method :eof, :eof?
150
151   def pos
152     raise IOError if closed?
153     sysseek(0, SEEK_CUR) - @buf.bytesize
154   end
155   alias_method :tell, :pos
156
157   def pos=(i)
158     seek(i, SEEK_SET)
159   end
160
161   def rewind
162     seek(0, SEEK_SET)
163   end
164
165   def seek(i, whence = SEEK_SET)
166     raise IOError if closed?
167     sysseek(i, whence)
168     @buf = ''
169     0
170   end
171
172   def _read_buf
173     return @buf if @buf && @buf.bytesize > 0
174     sysread(BUF_SIZE, @buf)
175   end
176
177   def ungetc(substr)
178     raise TypeError.new "expect String, got #{substr.class}" unless substr.is_a?(String)
179     if @buf.empty?
180       @buf.replace(substr)
181     else
182       @buf[0,0] = substr
183     end
184     nil
185   end
186
187   def read(length = nil, outbuf = "")
188     unless length.nil?
189       unless length.is_a? Fixnum
190         raise TypeError.new "can't convert #{length.class} into Integer"
191       end
192       if length < 0
193         raise ArgumentError.new "negative length: #{length} given"
194       end
195       if length == 0
196         return ""   # easy case
197       end
198     end
199
200     array = []
201     while 1
202       begin
203         _read_buf
204       rescue EOFError
205         array = nil if array.empty? and (not length.nil?) and length != 0
206         break
207       end
208
209       if length
210         consume = (length <= @buf.bytesize) ? length : @buf.bytesize
211         array.push IO._bufread(@buf, consume)
212         length -= consume
213         break if length == 0
214       else
215         array.push @buf
216         @buf = ''
217       end
218     end
219
220     if array.nil?
221       outbuf.replace("")
222       nil
223     else
224       outbuf.replace(array.join)
225     end
226   end
227
228   def readline(arg = "\n", limit = nil)
229     case arg
230     when String
231       rs = arg
232     when Fixnum
233       rs = "\n"
234       limit = arg
235     else
236       raise ArgumentError
237     end
238
239     if rs.nil?
240       return read
241     end
242
243     if rs == ""
244       rs = "\n\n"
245     end
246
247     array = []
248     while 1
249       begin
250         _read_buf
251       rescue EOFError
252         array = nil if array.empty?
253         break
254       end
255
256       if limit && limit <= @buf.size
257         array.push @buf[0, limit]
258         @buf[0, limit] = ""
259         break
260       elsif idx = @buf.index(rs)
261         len = idx + rs.size
262         array.push @buf[0, len]
263         @buf[0, len] = ""
264         break
265       else
266         array.push @buf
267         @buf = ''
268       end
269     end
270
271     raise EOFError.new "end of file reached" if array.nil?
272
273     array.join
274   end
275
276   def gets(*args)
277     begin
278       readline(*args)
279     rescue EOFError
280       nil
281     end
282   end
283
284   def readchar
285     _read_buf
286     _readchar(@buf)
287   end
288
289   def getc
290     begin
291       readchar
292     rescue EOFError
293       c = @buf[0]
294       @buf[0,1]="" if c
295       nil
296     end
297   end
298
299   # 15.2.20.5.3
300   def each(&block)
301     return to_enum unless block
302
303     while line = self.gets
304       block.call(line)
305     end
306     self
307   end
308
309   # 15.2.20.5.4
310   def each_byte(&block)
311     return to_enum(:each_byte) unless block
312
313     while char = self.getc
314       block.call(char)
315     end
316     self
317   end
318
319   # 15.2.20.5.5
320   alias each_line each
321
322   alias each_char each_byte
323
324   def readlines
325     ary = []
326     while (line = gets)
327       ary << line
328     end
329     ary
330   end
331
332   def puts(*args)
333     i = 0
334     len = args.size
335     while i < len
336       s = args[i].to_s
337       write s
338       write "\n" if (s[-1] != "\n")
339       i += 1
340     end
341     write "\n" if len == 0
342     nil
343   end
344
345   def print(*args)
346     i = 0
347     len = args.size
348     while i < len
349       write args[i].to_s
350       i += 1
351     end
352   end
353
354   def printf(*args)
355     write sprintf(*args)
356     nil
357   end
358
359   alias_method :to_i, :fileno
360   alias_method :tty?, :isatty
361 end
362
363 STDIN  = IO.open(0, "r")
364 STDOUT = IO.open(1, "w")
365 STDERR = IO.open(2, "w")
366
367 $stdin  = STDIN
368 $stdout = STDOUT
369 $stderr = STDERR