1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2004-2008 Jean Privat <jean@pryen.org>
4 # Copyright 2006-2008 Floréal Morandat <morandat@lirmm.fr>
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
14 # This module is about character strings.
19 ###############################################################################
21 ###############################################################################
23 abstract class AbstractString
24 special AbstractArrayRead[Char]
25 readable private var _items
: NativeString
27 redef fun [](index
) do return _items
[index
]
31 # "abcd".substring(1, 2) # --> "bc"
32 # "abcd".substring(-1, 2) # --> "a"
33 # "abcd".substring(1, 0) # --> ""
34 # "abcd".substring(2, 5) # --> "cd"
35 fun substring
(from
: Int, count
: Int): String
39 if from
< 0 then from
= 0
40 if count
> length
then count
= length
42 var r
= new Buffer.with_capacity
(count
- from
)
53 # Create a substring with the string beginning at the 'from' position
55 # "abcd".substring(1) # --> "bcd"
56 # "abcd".substring(-1) # --> "abcd"
57 # "abcd".substring(2) # --> "cd"
58 fun substring_from
(from
: Int): String
61 return substring
(from
, length
- from
)
64 # is this string a substring of the 'of' string from pos 'pos'
66 # "bc".is_substring("abcd",1) # --> true
67 # "bc".is_substring("abcd",2) # --> false
68 fun has_substring
(str
: String, pos
: Int): Bool
70 var itsindex
= str
.length
- 1
71 var myindex
= pos
+ itsindex
73 var itsitems
= str
._items
74 if myindex
> length
or itsindex
> myindex
then return false
75 while itsindex
>= 0 do
76 if myitems
[myindex
] != itsitems
[itsindex
] then return false
83 # Is this string prefixed by 'prefix'
85 # "abc".is_prefix("abcd") # --> true
86 # "bc".is_prefix("abcd") # --> false
87 fun has_prefix
(prefix
: String): Bool do return has_substring
(prefix
,0)
89 # Is this string suffixed by 'suffix'
91 # "abcd".has_suffix("abc") # --> false
92 # "abcd".has_suffix("bcd") # --> true
93 fun has_suffix
(suffix
: String): Bool do return has_substring
(suffix
, length
- suffix
.length
)
95 # If `self' contains only digits, return the corresponding integer
99 return to_s
.to_cstring
.atoi
102 # If `self' contains only digits and alpha <= 'f', return the corresponding integer.
103 fun to_hex
: Int do return a_to
(16)
105 # If `self' contains only digits and letters, return the corresponding integer in a given base
106 fun a_to
(base
: Int) : Int
133 # String to upper case
136 var s
= new Buffer.with_capacity
(length
)
137 for i
in self do s
.add
(i
.to_upper
)
141 # String to lower case
142 fun to_lower
: String
144 var s
= new Buffer.with_capacity
(length
)
145 for i
in self do s
.add
(i
.to_lower
)
163 special AbstractString
164 redef type OTHER: String
166 # Create a new string from a given char *.
167 init with_native
(nat
: NativeString, size
: Int)
174 # Create a new string from a null terminated char *.
175 init from_cstring
(str
: NativeString)
177 var size
= str
.cstring_length
182 # Return a null terminated char *
183 fun to_cstring
: NativeString
190 if not o
isa String or o
is null then return false
192 if o
.length
!= l
then return false
197 if it
[i
] != oit
[i
] then return false
210 while i
< l1
and i
< l2
do
227 # The concatenation of `self' with `r'
228 fun +(s
: String): String
230 var r
= new Buffer.with_capacity
(length
+ s
.length
)
236 # i repetitions of self
237 fun *(i
: Int): String
240 var r
= new Buffer.with_capacity
(length
* i
)
248 redef fun to_s
do return self
251 # Strings are arrays of characters.
253 special AbstractString
255 special StringCapable
256 special AbstractArray[Char]
258 redef type OTHER: String
260 redef fun []=(index
, item
)
262 if index
== length
then
266 assert index
>= 0 and index
< length
272 if _capacity
<= length
then enlarge
(length
+ 5)
277 redef fun enlarge
(cap
)
280 if cap
<= c
then return
281 while c
<= cap
do c
= c
* 2 + 2
282 var a
= calloc_string
(c
+1)
283 _items
.copy_to
(a
, length
, 0, 0)
292 if _capacity
< length
+ sl
then enlarge
(length
+ sl
)
293 s
.items
.copy_to
(_items
, sl
, 0, length
)
300 redef fun to_s
: String
303 var a
= calloc_string
(l
+1)
304 _items
.copy_to
(a
, l
, 0, 0)
306 # Ensure the afterlast byte is '\0' to nul-terminated char *
309 return new String.with_native
(a
, length
)
317 while i
< l1
and i
< l2
do
318 var c1
= self[i
].ascii
334 # Create a new empty string.
342 _capacity
= s
.length
+ 1
344 _items
= calloc_string
(_capacity
)
345 s
.items
.copy_to
(_items
, _length
, 0, 0)
348 # Create a new empty string with a given capacity.
349 init with_capacity
(cap
: Int)
352 # _items = new NativeString.calloc(cap)
353 _items
= calloc_string
(cap
+1)
360 if not o
isa Buffer or o
is null then return false
362 if o
.length
!= l
then return false
367 if it
[i
] != oit
[i
] then return false
373 readable private var _capacity
: Int
376 ###############################################################################
378 ###############################################################################
381 # fun class_name: String is extern intern # The name of the class
383 # User redeable representation of `self'.
384 fun to_s
: String do return inspect
386 # Developper readable representation of `self'.
387 # Usualy, it uses the form "<CLASSNAME:#OBJECTID bla bla bla>"
395 # Return "<CLASSNAME:#OBJECTID".
396 # This fuction is mainly used with the redefinition of the inspect(0) method
397 protected fun inspect_head
: String
399 return "<{object_id.to_hex}"
402 protected fun args
: IndexedCollection[String]
420 fun fill_buffer
(s
: Buffer, base
: Int, signed
: Bool)
421 # Fill `s' with the digits in base 'base' of `self' (and with the '-' sign if 'signed' and negative).
422 # assume < to_c max const of char
429 else if self == 0 then
436 var pos
= digit_count
(base
) - 1
437 while pos
>= 0 and n
> 0 do
438 s
[pos
] = (n
% base
).to_c
444 # return displayable int in base 10 and signed
445 redef fun to_s
do return to_base
(10,true)
447 # return displayable int in hexadecimal (unsigned (not now))
448 fun to_hex
: String do return to_base
(16,false)
450 # return displayable int in base base and signed
451 fun to_base
(base
: Int, signed
: Bool): String
453 var l
= digit_count
(base
)
454 var s
= new Buffer.from
(" " * l
)
455 fill_buffer
(s
, base
, signed
)
461 redef fun to_s
do return to_precision
(6)
463 # `self' representation with `nb' digits after the '.'.
464 fun to_precision
(nb
: Int): String
466 if nb
== 0 then return to_i
.to_s
474 var d
= ((self-i
.to_f
)*dec
).to_i
482 var s
= new Buffer.with_capacity
(1)
488 redef class Collection[E
]
489 # Concatenate elements.
493 for e
in self do if e
!= null then s
.append
(e
.to_s
)
497 # Concatenate and separate each elements with `sep'.
498 fun join
(sep
: String): String
500 if is_empty
then return ""
502 var s
= new Buffer # Result
507 if e
!= null then s
.append
(e
.to_s
)
514 if e
!= null then s
.append
(e
.to_s
)
522 # Fast implementation
530 if e
!= null then s
.append
(e
.to_s
)
538 # Concatenate couple of 'key value' separate by 'couple_sep' and separate each couple with `sep'.
539 fun map_join
(sep
: String, couple_sep
: String): String
541 if is_empty
then return ""
543 var s
= new Buffer # Result
549 if e
!= null then s
.append
("{k}{couple_sep}{e}")
557 if e
!= null then s
.append
("{k}{couple_sep}{e}")
564 ###############################################################################
566 ###############################################################################
568 # Native strings are simple C char *
570 fun [](index
: Int): Char is intern
571 fun []=(index
: Int, item
: Char) is intern
572 fun copy_to
(dest
: NativeString, length
: Int, from
: Int, to
: Int) is intern
574 # Position of the first nul character.
575 fun cstring_length
: Int
578 while self[l
] != '\0' do l
+= 1
581 fun atoi
: Int is intern
584 # StringCapable objects can create native strings
586 protected fun calloc_string
(size
: Int): NativeString is intern
590 var _args_cache
: nullable IndexedCollection[String]
592 redef fun args
: IndexedCollection[String]
594 if _args_cache
== null then init_args
595 return _args_cache
.as(not null)
598 # The name of the program as given by the OS
599 fun program_name
: String
601 return new String.from_cstring
(native_argv
(0))
604 # Initialize `args' with the contents of `native_argc' and `native_argv'.
605 private fun init_args
607 var argc
= native_argc
608 var args
= new Array[String].with_capacity
(0)
611 args
[i-1
] = new String.from_cstring
(native_argv
(i
))
617 private fun native_argc
: Int is extern "kernel_Sys_Sys_native_argc_0" # First argument of the main C function.
619 private fun native_argv
(i
: Int): NativeString is extern "kernel_Sys_Sys_native_argv_1" # Second argument of the main C function.