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 # Basic manipulations of strings of characters
17 intrude import collection
# FIXME should be collection::array
20 ###############################################################################
22 ###############################################################################
24 # Common subclass for String and Buffer
25 abstract class AbstractString
26 super AbstractArrayRead[Char]
28 readable private var _items
: NativeString
30 redef fun [](index
) do return _items
[index
]
34 # "abcd".substring(1, 2) # --> "bc"
35 # "abcd".substring(-1, 2) # --> "a"
36 # "abcd".substring(1, 0) # --> ""
37 # "abcd".substring(2, 5) # --> "cd"
38 fun substring
(from
: Int, count
: Int): String
42 if from
< 0 then from
= 0
43 if count
> length
then count
= length
45 var r
= new Buffer.with_capacity
(count
- from
)
56 # Create a substring from `self' beginning at the 'from' position
58 # "abcd".substring(1) # --> "bcd"
59 # "abcd".substring(-1) # --> "abcd"
60 # "abcd".substring(2) # --> "cd"
61 fun substring_from
(from
: Int): String
64 return substring
(from
, length
- from
)
67 # Is `self' a substring of the `str' string from pos `pos'
69 # "bc".is_substring("abcd",1) # --> true
70 # "bc".is_substring("abcd",2) # --> false
71 fun has_substring
(str
: String, pos
: Int): Bool
73 var itsindex
= str
.length
- 1
74 var myindex
= pos
+ itsindex
76 var itsitems
= str
._items
77 if myindex
> length
or itsindex
> myindex
then return false
78 while itsindex
>= 0 do
79 if myitems
[myindex
] != itsitems
[itsindex
] then return false
86 # Is this string prefixed by 'prefix'
88 # "abc".is_prefix("abcd") # --> true
89 # "bc".is_prefix("abcd") # --> false
90 fun has_prefix
(prefix
: String): Bool do return has_substring
(prefix
,0)
92 # Is this string suffixed by 'suffix'
94 # "abcd".has_suffix("abc") # --> false
95 # "abcd".has_suffix("bcd") # --> true
96 fun has_suffix
(suffix
: String): Bool do return has_substring
(suffix
, length
- suffix
.length
)
98 # If `self' contains only digits, return the corresponding integer
102 return to_s
.to_cstring
.atoi
105 # If `self' contains a float, return the corresponding float
109 return to_s
.to_cstring
.atof
112 # If `self' contains only digits and alpha <= 'f', return the corresponding integer.
113 fun to_hex
: Int do return a_to
(16)
115 # If `self' contains only digits and letters, return the corresponding integer in a given base
116 fun a_to
(base
: Int) : Int
143 # A upper case version of `self'
146 var s
= new Buffer.with_capacity
(length
)
147 for i
in self do s
.add
(i
.to_upper
)
151 # A lower case version of `self'
152 fun to_lower
: String
154 var s
= new Buffer.with_capacity
(length
)
155 for i
in self do s
.add
(i
.to_lower
)
170 # Immutable strings of characters.
175 redef type OTHER: String
177 # Create a new string from a given char *.
178 init with_native
(nat
: NativeString, size
: Int)
185 # Create a new string from a null terminated char *.
186 init from_cstring
(str
: NativeString)
188 var size
= str
.cstring_length
193 # Return a null terminated char *
194 fun to_cstring
: NativeString
201 if not o
isa String or o
is null then return false
203 if o
.length
!= l
then return false
208 if it
[i
] != oit
[i
] then return false
221 while i
< l1
and i
< l2
do
238 # The concatenation of `self' with `r'
239 fun +(s
: String): String
241 var r
= new Buffer.with_capacity
(length
+ s
.length
)
247 # i repetitions of self
248 fun *(i
: Int): String
251 var r
= new Buffer.with_capacity
(length
* i
)
259 redef fun to_s
do return self
263 # djb2 hash algorythm
268 h
= (h
* 32) + h
+ it
[i
].ascii
276 # Mutable strings of characters.
281 super AbstractArray[Char]
283 redef type OTHER: String
285 redef fun []=(index
, item
)
287 if index
== length
then
291 assert index
>= 0 and index
< length
297 if _capacity
<= length
then enlarge
(length
+ 5)
302 redef fun enlarge
(cap
)
305 if cap
<= c
then return
306 while c
<= cap
do c
= c
* 2 + 2
307 var a
= calloc_string
(c
+1)
308 _items
.copy_to
(a
, length
, 0, 0)
317 if _capacity
< length
+ sl
then enlarge
(length
+ sl
)
318 s
.items
.copy_to
(_items
, sl
, 0, length
)
325 redef fun to_s
: String
328 var a
= calloc_string
(l
+1)
329 _items
.copy_to
(a
, l
, 0, 0)
331 # Ensure the afterlast byte is '\0' to nul-terminated char *
334 return new String.with_native
(a
, length
)
342 while i
< l1
and i
< l2
do
343 var c1
= self[i
].ascii
359 # Create a new empty string.
367 _capacity
= s
.length
+ 1
369 _items
= calloc_string
(_capacity
)
370 s
.items
.copy_to
(_items
, _length
, 0, 0)
373 # Create a new empty string with a given capacity.
374 init with_capacity
(cap
: Int)
377 # _items = new NativeString.calloc(cap)
378 _items
= calloc_string
(cap
+1)
385 if not o
isa Buffer or o
is null then return false
387 if o
.length
!= l
then return false
392 if it
[i
] != oit
[i
] then return false
398 readable private var _capacity
: Int
401 ###############################################################################
403 ###############################################################################
406 # User readable representation of `self'.
407 fun to_s
: String do return inspect
409 # The class name of the object in NativeString format.
410 private fun native_class_name
: NativeString is intern
412 # The class name of the object.
413 # FIXME: real type information is not available at runtime.
414 # Therefore, for instance, an instance of List[Bool] has just
415 # "List" for class_name
416 fun class_name
: String do return new String.from_cstring
(native_class_name
)
418 # Developer readable representation of `self'.
419 # Usually, it uses the form "<CLASSNAME:#OBJECTID bla bla bla>"
422 return "<{inspect_head}>"
425 # Return "CLASSNAME:#OBJECTID".
426 # This function is mainly used with the redefinition of the inspect method
427 protected fun inspect_head
: String
429 return "{class_name}:#{object_id.to_hex}"
432 protected fun args
: Sequence[String]
450 fun fill_buffer
(s
: Buffer, base
: Int, signed
: Bool)
451 # Fill `s' with the digits in base 'base' of `self' (and with the '-' sign if 'signed' and negative).
452 # assume < to_c max const of char
459 else if self == 0 then
466 var pos
= digit_count
(base
) - 1
467 while pos
>= 0 and n
> 0 do
468 s
[pos
] = (n
% base
).to_c
474 # return displayable int in base 10 and signed
475 redef fun to_s
do return to_base
(10,true)
477 # return displayable int in hexadecimal (unsigned (not now))
478 fun to_hex
: String do return to_base
(16,false)
480 # return displayable int in base base and signed
481 fun to_base
(base
: Int, signed
: Bool): String
483 var l
= digit_count
(base
)
484 var s
= new Buffer.from
(" " * l
)
485 fill_buffer
(s
, base
, signed
)
491 # Pretty print self, print needed decimals up to a max of 6.
493 var str
= to_precision
( 6 )
495 for i
in [0..len-1
] do
500 else if c
== '.' then
501 return str
.substring
( 0, j
+2 )
503 return str
.substring
( 0, j
+1 )
509 # `self' representation with `nb' digits after the '.'.
510 fun to_precision
(nb
: Int): String import String::from_cstring
`{
514 size = snprintf(NULL, 0, "%.*f", (int)nb, recv);
515 str = malloc(size + 1);
516 sprintf(str, "%.*f", (int)nb, recv );
518 return new_String_from_cstring( str );
525 var s
= new Buffer.with_capacity
(1)
531 redef class Collection[E
]
532 # Concatenate elements.
536 for e
in self do if e
!= null then s
.append
(e
.to_s
)
540 # Concatenate and separate each elements with `sep'.
541 fun join
(sep
: String): String
543 if is_empty
then return ""
545 var s
= new Buffer # Result
550 if e
!= null then s
.append
(e
.to_s
)
557 if e
!= null then s
.append
(e
.to_s
)
565 # Fast implementation
573 if e
!= null then s
.append
(e
.to_s
)
581 # Concatenate couple of 'key value'.
582 # key and value are separated by 'couple_sep'.
583 # each couple is separated each couple with `sep'.
584 fun join
(sep
: String, couple_sep
: String): String
586 if is_empty
then return ""
588 var s
= new Buffer # Result
594 if e
!= null then s
.append
("{k}{couple_sep}{e}")
602 if e
!= null then s
.append
("{k}{couple_sep}{e}")
609 ###############################################################################
611 ###############################################################################
613 # Native strings are simple C char *
615 fun [](index
: Int): Char is intern
616 fun []=(index
: Int, item
: Char) is intern
617 fun copy_to
(dest
: NativeString, length
: Int, from
: Int, to
: Int) is intern
619 # Position of the first nul character.
620 fun cstring_length
: Int
623 while self[l
] != '\0' do l
+= 1
626 fun atoi
: Int is intern
627 fun atof
: Float is extern "atof"
630 # StringCapable objects can create native strings
631 interface StringCapable
632 protected fun calloc_string
(size
: Int): NativeString is intern
636 var _args_cache
: nullable Sequence[String]
638 redef fun args
: Sequence[String]
640 if _args_cache
== null then init_args
641 return _args_cache
.as(not null)
644 # The name of the program as given by the OS
645 fun program_name
: String
647 return new String.from_cstring
(native_argv
(0))
650 # Initialize `args' with the contents of `native_argc' and `native_argv'.
651 private fun init_args
653 var argc
= native_argc
654 var args
= new Array[String].with_capacity
(0)
657 args
[i-1
] = new String.from_cstring
(native_argv
(i
))
663 private fun native_argc
: Int is extern "kernel_Sys_Sys_native_argc_0" # First argument of the main C function.
665 private fun native_argv
(i
: Int): NativeString is extern "kernel_Sys_Sys_native_argv_1" # Second argument of the main C function.