lib: fix import of stdio.h for String::to_precision
[nit.git] / lib / standard / string.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2004-2008 Jean Privat <jean@pryen.org>
4 # Copyright 2006-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 # Basic manipulations of strings of characters
15 package string
16
17 intrude import collection # FIXME should be collection::array
18 import hash
19
20 `{
21 #include <stdio.h>
22 `}
23
24 ###############################################################################
25 # String #
26 ###############################################################################
27
28 # Common subclass for String and Buffer
29 abstract class AbstractString
30 super AbstractArrayRead[Char]
31
32 readable private var _items: NativeString
33
34 redef fun [](index) do return _items[index]
35
36 # Create a substring.
37 #
38 # "abcd".substring(1, 2) # --> "bc"
39 # "abcd".substring(-1, 2) # --> "a"
40 # "abcd".substring(1, 0) # --> ""
41 # "abcd".substring(2, 5) # --> "cd"
42 fun substring(from: Int, count: Int): String
43 do
44 assert count >= 0
45 count += from
46 if from < 0 then from = 0
47 if count > length then count = length
48 if from < count then
49 var r = new Buffer.with_capacity(count - from)
50 while from < count do
51 r.push(_items[from])
52 from += 1
53 end
54 return r.to_s
55 else
56 return ""
57 end
58 end
59
60 # Create a substring from `self' beginning at the 'from' position
61 #
62 # "abcd".substring(1) # --> "bcd"
63 # "abcd".substring(-1) # --> "abcd"
64 # "abcd".substring(2) # --> "cd"
65 fun substring_from(from: Int): String
66 do
67 assert from < length
68 return substring(from, length - from)
69 end
70
71 # Does self have a substring 'str' starting from position 'pos
72 #
73 # "abcd".has_substring("bc",1) # --> true
74 # "abcd".has_substring("bc",2) # --> false
75 fun has_substring(str: String, pos: Int): Bool
76 do
77 var itsindex = str.length - 1
78 var myindex = pos + itsindex
79 var myitems = _items
80 var itsitems = str._items
81 if myindex > length or itsindex > myindex then return false
82 var its_index_from = str._index_from
83 itsindex += its_index_from
84 while itsindex >= its_index_from do
85 if myitems[myindex] != itsitems[itsindex] then return false
86 myindex -= 1
87 itsindex -= 1
88 end
89 return true
90 end
91
92 # Is this string prefixed by 'prefix'
93 #
94 # "abc".is_prefix("abcd") # --> true
95 # "bc".is_prefix("abcd") # --> false
96 fun has_prefix(prefix: String): Bool do return has_substring(prefix,0)
97
98 # Is this string suffixed by 'suffix'
99 #
100 # "abcd".has_suffix("abc") # --> false
101 # "abcd".has_suffix("bcd") # --> true
102 fun has_suffix(suffix: String): Bool do return has_substring(suffix, length - suffix.length)
103
104 # If `self' contains only digits, return the corresponding integer
105 fun to_i: Int
106 do
107 # Shortcut
108 return to_s.to_cstring.atoi
109 end
110
111 # If `self' contains a float, return the corresponding float
112 fun to_f: Float
113 do
114 # Shortcut
115 return to_s.to_cstring.atof
116 end
117
118 # If `self' contains only digits and alpha <= 'f', return the corresponding integer.
119 fun to_hex: Int do return a_to(16)
120
121 # If `self' contains only digits and letters, return the corresponding integer in a given base
122 fun a_to(base: Int) : Int
123 do
124 var i = 0
125 var neg = false
126
127 for c in self
128 do
129 var v = c.to_i
130 if v > base then
131 if neg then
132 return -i
133 else
134 return i
135 end
136 else if v < 0 then
137 neg = true
138 else
139 i = i * base + v
140 end
141 end
142 if neg then
143 return -i
144 else
145 return i
146 end
147 end
148
149 # Returns true if the string contains only Numeric values (and one "," or one "." character)
150 fun is_numeric: Bool
151 do
152 var has_point_or_comma = false
153 for i in self
154 do
155 if not i.is_numeric
156 then
157 if (i == '.' or i == ',') and not has_point_or_comma
158 then
159 has_point_or_comma = true
160 else
161 return false
162 end
163 end
164 end
165 return true
166 end
167
168 # A upper case version of `self'
169 fun to_upper: String
170 do
171 var s = new Buffer.with_capacity(length)
172 for i in self do s.add(i.to_upper)
173 return s.to_s
174 end
175
176 # A lower case version of `self'
177 fun to_lower : String
178 do
179 var s = new Buffer.with_capacity(length)
180 for i in self do s.add(i.to_lower)
181 return s.to_s
182 end
183
184 # Trims trailing and preceding white spaces
185 # A whitespace is defined as any character which ascii value is less than or equal to 32
186 fun trim: String
187 do
188 if self._length == 0 then return self.to_s
189 # find position of the first non white space char (ascii < 32) from the start of the string
190 var start_pos = 0
191 while self[start_pos].ascii <= 32 do
192 start_pos += 1
193 if start_pos == _length then return ""
194 end
195 # find position of the first non white space char from the end of the string
196 var end_pos = length - 1
197 while self[end_pos].ascii <= 32 do
198 end_pos -= 1
199 if end_pos == start_pos then return self[start_pos].to_s
200 end
201 return self.substring(start_pos, end_pos - start_pos + 1)
202 end
203
204 redef fun output
205 do
206 var i = 0
207 while i < length do
208 _items[i].output
209 i += 1
210 end
211 end
212 end
213
214 # Immutable strings of characters.
215 class String
216 super Comparable
217 super AbstractString
218 super StringCapable
219
220 redef type OTHER: String
221
222 # Index in _items of the start of the string
223 readable var _index_from: Int
224
225 # Indes in _items of the last item of the string
226 readable var _index_to: Int
227
228 ################################################
229 # AbstractString specific methods #
230 ################################################
231
232 # Access a character at index in String
233 #
234 redef fun [](index) do
235 assert index >= 0
236 # Check that the index (+ index_from) is not larger than indexTo
237 # In other terms, if the index is valid
238 assert (index + _index_from) <= _index_to
239 return _items[index + _index_from]
240 end
241
242 # Create a substring.
243 #
244 # "abcd".substring(1, 2) # --> "bc"
245 # "abcd".substring(-1, 2) # --> "a"
246 # "abcd".substring(1, 0) # --> ""
247 # "abcd".substring(2, 5) # --> "cd"
248 #
249 # A "from" index < 0 will be replaced by 0
250 # Unless a count value is > 0 at the same time
251 # In this case, from += count and count -= from
252 #
253 redef fun substring(from: Int, count: Int): String
254 do
255 assert count >= 0
256
257 if from < 0 then
258 count += from
259 if count < 0 then count = 0
260 from = 0
261 end
262
263 var realFrom = _index_from + from
264
265 if (realFrom + count) > _index_to then return new String.from_substring(realFrom, _index_to, _items)
266
267 if count == 0 then return ""
268
269 return new String.from_substring(realFrom, realFrom + count - 1, _items)
270 end
271
272 # Create a substring from `self' beginning at the 'from' position
273 #
274 # "abcd".substring_from(1) # --> "bcd"
275 # "abcd".substring_from(-1) # --> "abcd"
276 # "abcd".substring_from(2) # --> "cd"
277 #
278 # As with substring, a "from" index < 0 will be replaced by 0
279 #
280 redef fun substring_from(from: Int): String
281 do
282 if from > _length then return ""
283 if from < 0 then from = 0
284 return substring(from, _length)
285 end
286
287 # Does self have a substring 'str' starting from position 'pos
288 #
289 # "abcd".has_substring("bc",1) # --> true
290 # "abcd".has_substring("bc",2) # --> false
291 redef fun has_substring(str: String, pos: Int): Bool
292 do
293 var itsindex = str._length - 1
294
295 var myindex = pos + itsindex
296 var myitems = _items
297
298 var itsitems = str._items
299
300 if myindex > _length or itsindex > myindex then return false
301
302 var itsindexfrom = str.index_from
303 itsindex += itsindexfrom
304 myindex += index_from
305
306 while itsindex >= itsindexfrom do
307 if myitems[myindex] != itsitems[itsindex] then return false
308 myindex -= 1
309 itsindex -= 1
310 end
311
312 return true
313 end
314
315 # A upper case version of `self'
316 redef fun to_upper: String
317 do
318 var outstr = calloc_string(self._length + 1)
319 var out_index = 0
320
321 var myitems = self._items
322 var index_from = self._index_from
323 var max = self._index_to
324
325 while index_from <= max do
326 outstr[out_index] = myitems[index_from].to_upper
327 out_index += 1
328 index_from += 1
329 end
330
331 outstr[self.length] = '\0'
332
333 return new String.with_native(outstr, self._length)
334 end
335
336 # A lower case version of `self'
337 redef fun to_lower : String
338 do
339 var outstr = calloc_string(self._length + 1)
340 var out_index = 0
341
342 var myitems = self._items
343 var index_from = self._index_from
344 var max = self._index_to
345
346 while index_from <= max do
347 outstr[out_index] = myitems[index_from].to_lower
348 out_index += 1
349 index_from += 1
350 end
351
352 outstr[self.length] = '\0'
353
354 return new String.with_native(outstr, self._length)
355 end
356
357 redef fun trim: String
358 do
359 if self._length == 0 then return self
360 # find position of the first non white space char (ascii < 32) from the start of the string
361 var start_pos = self._index_from
362 while _items[start_pos].ascii <= 32 do
363 start_pos += 1
364 if start_pos == _index_to + 1 then return ""
365 end
366 # find position of the first non white space char from the end of the string
367 var end_pos = _index_to
368 while _items[end_pos].ascii <= 32 do
369 end_pos -= 1
370 if end_pos == start_pos then return _items[start_pos].to_s
371 end
372 start_pos -= index_from
373 end_pos -= index_from
374 return self.substring(start_pos, end_pos - start_pos + 1)
375 end
376
377 redef fun output
378 do
379 var i = self._index_from
380 var imax = self._index_to
381 while i <= imax do
382 _items[i].output
383 i += 1
384 end
385 end
386
387 ##################################################
388 # String Specific Methods #
389 ##################################################
390
391 # Creates a String object as a substring of another String
392 #
393 # From : index to start at
394 #
395 # To : Index to stop at (from + count -1)
396 #
397 private init from_substring(from: Int, to: Int, internalString: NativeString)
398 do
399 _items = internalString
400 _index_from = from
401 _index_to = to
402 _length = to - from + 1
403 end
404
405 # Create a new string from a given char *.
406 init with_native(nat: NativeString, size: Int)
407 do
408 assert size >= 0
409 _items = nat
410 _length = size
411 _index_from = 0
412 _index_to = _length - 1
413 end
414
415 # Create a new string from a null terminated char *.
416 init from_cstring(str: NativeString)
417 do
418 with_native(str,str.cstring_length)
419 end
420
421 # Creates a new Nit String from an existing CString
422 # Pretty much equals to from_cstring but copies instead
423 # of passing a reference
424 # Avoids manual/automatic dealloc problems when dealing with native C code
425 init copy_from_native(str: NativeString)
426 do
427 var temp_length = str.cstring_length
428 var new_str = calloc_string(temp_length + 1)
429 str.copy_to(new_str, temp_length, 0, 0)
430 new_str[temp_length] = '\0'
431 with_native(new_str, temp_length)
432 end
433
434 # Return a null terminated char *
435 fun to_cstring: NativeString
436 do
437 #return items
438 if _index_from > 0 or _index_to != items.cstring_length - 1 then
439 var newItems = calloc_string(_length + 1)
440 self.items.copy_to(newItems, _length, _index_from, 0)
441 newItems[length] = '\0'
442 return newItems
443 end
444 return _items
445 end
446
447 redef fun ==(other)
448 do
449 if not other isa String or other is null then return false
450
451 if self.object_id == other.object_id then return true
452
453 var my_length = _length
454
455 if other._length != my_length then return false
456
457 var my_index = _index_from
458 var its_index = other._index_from
459
460 var last_iteration = my_index + my_length
461
462 var itsitems = other._items
463 var myitems = self._items
464
465 while my_index < last_iteration do
466 if myitems[my_index] != itsitems[its_index] then return false
467 my_index += 1
468 its_index += 1
469 end
470
471 return true
472 end
473
474 # The comparison between two strings is done on a lexicographical basis
475 # Eg : "aa" < "b" => true
476 redef fun <(other)
477 do
478 if self.object_id == other.object_id then return false
479
480 var my_curr_char : Char
481 var its_curr_char : Char
482
483 var curr_id_self = self._index_from
484 var curr_id_other = other._index_from
485
486 var my_items = self._items
487 var its_items = other._items
488
489 var my_length = self._length
490 var its_length = other._length
491
492 var max_iterations = curr_id_self + my_length
493
494 while curr_id_self < max_iterations do
495 my_curr_char = my_items[curr_id_self]
496 its_curr_char = its_items[curr_id_other]
497
498 if my_curr_char != its_curr_char then
499 if my_curr_char < its_curr_char then return true
500 return false
501 end
502
503 curr_id_self += 1
504 curr_id_other += 1
505 end
506
507 return my_length < its_length
508 end
509
510 # The concatenation of `self' with `r'
511 fun +(s: String): String
512 do
513 var my_length = self._length
514 var its_length = s._length
515
516 var target_string = calloc_string(my_length + its_length + 1)
517
518 self._items.copy_to(target_string, my_length, _index_from, 0)
519 s._items.copy_to(target_string, its_length, s._index_from, my_length)
520
521 target_string[my_length + its_length] = '\0'
522
523 return new String.with_native(target_string, my_length + its_length)
524 end
525
526 # i repetitions of self
527 fun *(i: Int): String
528 do
529 assert i >= 0
530
531 var my_length = self._length
532
533 var final_length = my_length * i
534
535 var my_items = self._items
536
537 var target_string = calloc_string((final_length) + 1)
538
539 target_string[final_length] = '\0'
540
541 var current_last = 0
542
543 for iteration in [1 .. i] do
544 my_items.copy_to(target_string, my_length, 0, current_last)
545 current_last += my_length
546 end
547
548 return new String.with_native(target_string, final_length)
549 end
550
551 redef fun to_s do return self
552
553 redef fun hash
554 do
555 # djb2 hash algorythm
556 var h = 5381
557 var i = _length - 1
558
559 var myitems = _items
560 var strStart = _index_from
561
562 i += strStart
563
564 while i >= strStart do
565 h = (h * 32) + h + self._items[i].ascii
566 i -= 1
567 end
568
569 return h
570 end
571 end
572
573 # Mutable strings of characters.
574 class Buffer
575 super AbstractString
576 super Comparable
577 super StringCapable
578 super AbstractArray[Char]
579
580 redef type OTHER: String
581
582 redef fun []=(index, item)
583 do
584 if index == length then
585 add(item)
586 return
587 end
588 assert index >= 0 and index < length
589 _items[index] = item
590 end
591
592 redef fun add(c)
593 do
594 if _capacity <= length then enlarge(length + 5)
595 _items[length] = c
596 _length += 1
597 end
598
599 redef fun enlarge(cap)
600 do
601 var c = _capacity
602 if cap <= c then return
603 while c <= cap do c = c * 2 + 2
604 var a = calloc_string(c+1)
605 _items.copy_to(a, length, 0, 0)
606 _items = a
607 _capacity = c
608 end
609
610 redef fun append(s)
611 do
612 if s isa String then
613 var sl = s.length
614 if _capacity < _length + sl then enlarge(_length + sl)
615 s.items.copy_to(_items, sl, s._index_from, _length)
616 _length += sl
617 else
618 super
619 end
620 end
621
622 redef fun to_s: String
623 do
624 var l = length
625 var a = calloc_string(l+1)
626 _items.copy_to(a, l, 0, 0)
627
628 # Ensure the afterlast byte is '\0' to nul-terminated char *
629 a[length] = '\0'
630
631 return new String.with_native(a, length)
632 end
633
634 redef fun <(s)
635 do
636 var i = 0
637 var l1 = length
638 var l2 = s.length
639 while i < l1 and i < l2 do
640 var c1 = self[i].ascii
641 var c2 = s[i].ascii
642 if c1 < c2 then
643 return true
644 else if c2 < c1 then
645 return false
646 end
647 i += 1
648 end
649 if l1 < l2 then
650 return true
651 else
652 return false
653 end
654 end
655
656 # Create a new empty string.
657 init
658 do
659 with_capacity(5)
660 end
661
662 init from(s: String)
663 do
664 _capacity = s.length + 1
665 _length = s.length
666 _items = calloc_string(_capacity)
667 s.items.copy_to(_items, _length, s._index_from, 0)
668 end
669
670 # Create a new empty string with a given capacity.
671 init with_capacity(cap: Int)
672 do
673 assert cap >= 0
674 # _items = new NativeString.calloc(cap)
675 _items = calloc_string(cap+1)
676 _capacity = cap
677 _length = 0
678 end
679
680 redef fun ==(o)
681 do
682 if not o isa Buffer or o is null then return false
683 var l = length
684 if o.length != l then return false
685 var i = 0
686 var it = _items
687 var oit = o._items
688 while i < l do
689 if it[i] != oit[i] then return false
690 i += 1
691 end
692 return true
693 end
694
695 readable private var _capacity: Int
696 end
697
698 ###############################################################################
699 # Refinement #
700 ###############################################################################
701
702 redef class Object
703 # User readable representation of `self'.
704 fun to_s: String do return inspect
705
706 # The class name of the object in NativeString format.
707 private fun native_class_name: NativeString is intern
708
709 # The class name of the object.
710 # FIXME: real type information is not available at runtime.
711 # Therefore, for instance, an instance of List[Bool] has just
712 # "List" for class_name
713 fun class_name: String do return new String.from_cstring(native_class_name)
714
715 # Developer readable representation of `self'.
716 # Usually, it uses the form "<CLASSNAME:#OBJECTID bla bla bla>"
717 fun inspect: String
718 do
719 return "<{inspect_head}>"
720 end
721
722 # Return "CLASSNAME:#OBJECTID".
723 # This function is mainly used with the redefinition of the inspect method
724 protected fun inspect_head: String
725 do
726 return "{class_name}:#{object_id.to_hex}"
727 end
728
729 protected fun args: Sequence[String]
730 do
731 return sys.args
732 end
733 end
734
735 redef class Bool
736 redef fun to_s
737 do
738 if self then
739 return once "true"
740 else
741 return once "false"
742 end
743 end
744 end
745
746 redef class Int
747 fun fill_buffer(s: Buffer, base: Int, signed: Bool)
748 # Fill `s' with the digits in base 'base' of `self' (and with the '-' sign if 'signed' and negative).
749 # assume < to_c max const of char
750 do
751 var n: Int
752 # Sign
753 if self < 0 then
754 n = - self
755 s[0] = '-'
756 else if self == 0 then
757 s[0] = '0'
758 return
759 else
760 n = self
761 end
762 # Fill digits
763 var pos = digit_count(base) - 1
764 while pos >= 0 and n > 0 do
765 s[pos] = (n % base).to_c
766 n = n / base # /
767 pos -= 1
768 end
769 end
770
771 # return displayable int in base 10 and signed
772 redef fun to_s do return to_base(10,true)
773
774 # return displayable int in hexadecimal (unsigned (not now))
775 fun to_hex: String do return to_base(16,false)
776
777 # return displayable int in base base and signed
778 fun to_base(base: Int, signed: Bool): String
779 do
780 var l = digit_count(base)
781 var s = new Buffer.from(" " * l)
782 fill_buffer(s, base, signed)
783 return s.to_s
784 end
785 end
786
787 redef class Float
788 # Pretty print self, print needed decimals up to a max of 6.
789 redef fun to_s do
790 var str = to_precision( 3 )
791 var len = str.length
792 for i in [0..len-1] do
793 var j = len-1-i
794 var c = str[j]
795 if c == '0' then
796 continue
797 else if c == '.' then
798 return str.substring( 0, j+2 )
799 else
800 return str.substring( 0, j+1 )
801 end
802 end
803 return str
804 end
805
806 # `self' representation with `nb' digits after the '.'.
807 fun to_precision(nb: Int): String
808 do
809 if nb == 0 then return self.to_i.to_s
810 var f = self
811 for i in [0..nb[ do f = f * 10.0
812 if self > 0.0 then
813 f = f + 0.5
814 else
815 f = f - 0.5
816 end
817 var i = f.to_i
818 if i == 0 then return "0.0"
819 var s = i.to_s
820 var sl = s.length
821 if sl > nb then
822 var p1 = s.substring(0, s.length-nb)
823 var p2 = s.substring(s.length-nb, nb)
824 return p1 + "." + p2
825 else
826 return "0." + ("0"*(nb-sl)) + s
827 end
828 end
829
830 fun to_precision_native(nb: Int): String import String::from_cstring `{
831 int size;
832 char *str;
833
834 size = snprintf(NULL, 0, "%.*f", (int)nb, recv);
835 str = malloc(size + 1);
836 sprintf(str, "%.*f", (int)nb, recv );
837
838 return new_String_from_cstring( str );
839 `}
840 end
841
842 redef class Char
843 redef fun to_s
844 do
845 var s = new Buffer.with_capacity(1)
846 s[0] = self
847 return s.to_s
848 end
849
850 # Returns true if the char is a numerical digit
851 fun is_numeric: Bool
852 do
853 if self >= '0' and self <= '9'
854 then
855 return true
856 end
857 return false
858 end
859
860 # Returns true if the char is an alpha digit
861 fun is_alpha: Bool
862 do
863 if (self >= 'a' and self <= 'z') or (self >= 'A' and self <= 'Z') then return true
864 return false
865 end
866
867 # Returns true if the char is an alpha or a numeric digit
868 fun is_alphanumeric: Bool
869 do
870 if self.is_numeric or self.is_alpha then return true
871 return false
872 end
873 end
874
875 redef class Collection[E]
876 # Concatenate elements.
877 redef fun to_s
878 do
879 var s = new Buffer
880 for e in self do if e != null then s.append(e.to_s)
881 return s.to_s
882 end
883
884 # Concatenate and separate each elements with `sep'.
885 fun join(sep: String): String
886 do
887 if is_empty then return ""
888
889 var s = new Buffer # Result
890
891 # Concat first item
892 var i = iterator
893 var e = i.item
894 if e != null then s.append(e.to_s)
895
896 # Concat other items
897 i.next
898 while i.is_ok do
899 s.append(sep)
900 e = i.item
901 if e != null then s.append(e.to_s)
902 i.next
903 end
904 return s.to_s
905 end
906 end
907
908 redef class Array[E]
909 # Fast implementation
910 redef fun to_s
911 do
912 var s = new Buffer
913 var i = 0
914 var l = length
915 while i < l do
916 var e = self[i]
917 if e != null then s.append(e.to_s)
918 i += 1
919 end
920 return s.to_s
921 end
922 end
923
924 redef class Map[K,V]
925 # Concatenate couple of 'key value'.
926 # key and value are separated by 'couple_sep'.
927 # each couple is separated each couple with `sep'.
928 fun join(sep: String, couple_sep: String): String
929 do
930 if is_empty then return ""
931
932 var s = new Buffer # Result
933
934 # Concat first item
935 var i = iterator
936 var k = i.key
937 var e = i.item
938 if e != null then s.append("{k}{couple_sep}{e}")
939
940 # Concat other items
941 i.next
942 while i.is_ok do
943 s.append(sep)
944 k = i.key
945 e = i.item
946 if e != null then s.append("{k}{couple_sep}{e}")
947 i.next
948 end
949 return s.to_s
950 end
951 end
952
953 ###############################################################################
954 # Native classes #
955 ###############################################################################
956
957 # Native strings are simple C char *
958 class NativeString
959 fun [](index: Int): Char is intern
960 fun []=(index: Int, item: Char) is intern
961 fun copy_to(dest: NativeString, length: Int, from: Int, to: Int) is intern
962
963 # Position of the first nul character.
964 fun cstring_length: Int
965 do
966 var l = 0
967 while self[l] != '\0' do l += 1
968 return l
969 end
970 fun atoi: Int is intern
971 fun atof: Float is extern "atof"
972 end
973
974 # StringCapable objects can create native strings
975 interface StringCapable
976 protected fun calloc_string(size: Int): NativeString is intern
977 end
978
979 redef class Sys
980 var _args_cache: nullable Sequence[String]
981
982 redef fun args: Sequence[String]
983 do
984 if _args_cache == null then init_args
985 return _args_cache.as(not null)
986 end
987
988 # The name of the program as given by the OS
989 fun program_name: String
990 do
991 return new String.from_cstring(native_argv(0))
992 end
993
994 # Initialize `args' with the contents of `native_argc' and `native_argv'.
995 private fun init_args
996 do
997 var argc = native_argc
998 var args = new Array[String].with_capacity(0)
999 var i = 1
1000 while i < argc do
1001 args[i-1] = new String.from_cstring(native_argv(i))
1002 i += 1
1003 end
1004 _args_cache = args
1005 end
1006
1007 # First argument of the main C function.
1008 private fun native_argc: Int is intern
1009
1010 # Second argument of the main C function.
1011 private fun native_argv(i: Int): NativeString is intern
1012 end
1013