note description: "[ Platform specific encoding of Unicode strings. By default, UTF-8 on unix or UTF-16 on Windows. Mixed-encoding consideration ============================ Most operating systems have conventions for strings that are incompatible with Unicode. On UNIX, a string is just a null-terminated byte sequence, it does not follow any specific encoding. Usually the locale setting enables you to see the string the way you expect. On Windows, the sequence of names is made of null-terminated UTF-16 code unit sequence. Windows does not guarantee that the sequence is actually a valid UTF-16 sequence. In other words, when there is an invalid UTF-8 encoding on UNIX, or an invalid UTF-16 encoding on Windows, the string is not directly representable as a Unicode string. To make it possible to create and store strings in a textually representable form, the query string will create an encoded representation that can be then later used in make to create a NATIVE_STRING equivalent to the original string. The encoding is described in UTF_CONVERTER's note clause and is a fourth variant of the recommended practice for replacement characters in Unicode (see http://www.unicode.org/review/pr-121.html). ]" date: "$Date: 2020-05-19 14:32:38 +0000 (Tue, 19 May 2020) $" revision: "$Revision: 104260 $" class NATIVE_STRING create make, make_empty, make_from_pointer, make_from_raw_string feature {NONE} -- Initialization default_create -- Process instances of classes with no creation clause. -- (Default: do nothing.) -- (from ANY) do end make (a_string: READABLE_STRING_GENERAL) -- Initialize an instance of Current using a_string treated as a sequence -- of Unicode characters. require a_string_not_void: a_string /= Void do make_empty (a_string.count) set_string (a_string) end make_empty (a_length: INTEGER_32) -- Initialize an empty instance of Current that will accommodate a_length code units. -- The memory area is not initialized. require a_length_positive: a_length >= 0 do create managed_data.make ((a_length + 1) * unit_size) unit_count := 0 end make_from_pointer (a_pointer: POINTER) -- Initialize current from a_pointer, a platform system specific null-terminated string. require a_path_pointer_not_null: a_pointer /= default_pointer local l_count: INTEGER_32 do l_count := pointer_length_in_bytes (a_pointer) create managed_data.make_from_pointer (a_pointer, l_count + unit_size) unit_count := l_count // unit_size end make_from_raw_string (a_raw_string: like raw_string) -- Initialize current from a_raw_string. require a_raw_string_not_void: a_raw_string /= Void local i: INTEGER_32 do create managed_data.make (a_raw_string.count + unit_size) across a_raw_string as l_c loop managed_data.put_character (l_c.item, i) i := i + 1 end if {PLATFORM}.is_windows then managed_data.put_natural_16 (0, i) else managed_data.put_natural_8 (0, i) end unit_count := (managed_data.count - unit_size) // unit_size ensure set: raw_string.same_string (a_raw_string) end feature -- Access generating_type: TYPE [detachable NATIVE_STRING] -- Type of current object -- (type of which it is a direct instance) -- (from ANY) external "built_in" ensure -- from ANY generating_type_not_void: Result /= Void end generator: STRING_8 -- Name of current object's generating class -- (base class of the type of which it is a direct instance) -- (from ANY) external "built_in" ensure -- from ANY generator_not_void: Result /= Void generator_not_empty: not Result.is_empty end item: POINTER -- Get pointer to allocated area. do Result := managed_data.item ensure item_not_null: Result /= default_pointer end managed_data: MANAGED_POINTER -- Hold data of Current. raw_string: STRING_8 -- Sequence of bytes representing Current. local l_cstr: C_STRING do create l_cstr.make_shared_from_pointer_and_count (managed_data.item, managed_data.count) Result := l_cstr.substring_8 (1, managed_data.count - unit_size) end string: STRING_32 -- Representation of Current up to the first null character. local u: UTF_CONVERTER do if {PLATFORM}.is_windows then Result := u.utf_16_0_pointer_to_escaped_string_32 (managed_data) else Result := u.utf_8_0_pointer_to_escaped_string_32 (managed_data) end end substring (start_pos, end_pos: INTEGER_32): STRING_32 -- Copy of substring containing all code units at indices -- between start_pos and end_pos. require start_position_big_enough: start_pos >= 1 end_position_big_enough: start_pos <= end_pos + 1 end_position_not_too_big: end_pos <= (capacity // unit_size) local u: UTF_CONVERTER do create Result.make (end_pos - start_pos + 1) if {PLATFORM}.is_windows then u.utf_16_0_subpointer_into_escaped_string_32 (managed_data, start_pos - 1, end_pos - 1, False, Result) else Result := u.utf_8_0_pointer_to_escaped_string_32 (managed_data); u.utf_8_0_subpointer_into_escaped_string_32 (managed_data, start_pos - 1, end_pos - 1, False, Result) end ensure susbstring_not_void: Result /= Void end feature {NATIVE_STRING_HANDLER} -- Access pointer_length_in_bytes (a_ptr: POINTER): INTEGER_32 -- Length in bytes of a platform specific file name pointer, not -- including the null-terminating character. If size is too large -- to fit into an {INTEGER} instance, the size is truncated to -- {INTEGER_32}.max_value. -- (from NATIVE_STRING_HANDLER) require -- from NATIVE_STRING_HANDLER a_ptr_not_null: a_ptr /= default_pointer local l_length: NATURAL_64 do l_length := c_pointer_length_in_bytes (a_ptr) if l_length <= {INTEGER_32}.max_value.to_natural_64 then Result := l_length.to_integer_32 else Result := {INTEGER_32}.max_value end end feature -- Measurement bytes_count: INTEGER_32 -- Number of bytes used by Current not including the null terminating character. do Result := unit_count * unit_size ensure bytes_count_non_negative: Result >= 0 end capacity: INTEGER_32 -- Number of bytes in Current. do Result := managed_data.count end unit_count: INTEGER_32 -- Number of units used by Current not including the null terminating unit. unit_size: INTEGER_32 -- Size in bytes of a unit for storage. do if {PLATFORM}.is_windows then Result := 2 else Result := 1 end end feature -- Comparison frozen deep_equal (a: detachable ANY; b: like arg #1): BOOLEAN -- Are a and b either both void -- or attached to isomorphic object structures? -- (from ANY) do if a = Void then Result := b = Void else Result := b /= Void and then a.is_deep_equal (b) end ensure -- from ANY instance_free: class shallow_implies_deep: standard_equal (a, b) implies Result both_or_none_void: (a = Void) implies (Result = (b = Void)) same_type: (Result and (a /= Void)) implies (b /= Void and then a.same_type (b)) symmetric: Result implies deep_equal (b, a) end frozen equal (a: detachable ANY; b: like arg #1): BOOLEAN -- Are a and b either both void or attached -- to objects considered equal? -- (from ANY) do if a = Void then Result := b = Void else Result := b /= Void and then a.is_equal (b) end ensure -- from ANY instance_free: class definition: Result = (a = Void and b = Void) or else ((a /= Void and b /= Void) and then a.is_equal (b)) end frozen is_deep_equal alias "≡≡≡" (other: NATIVE_STRING): BOOLEAN -- Are Current and other attached to isomorphic object structures? -- (from ANY) require -- from ANY other_not_void: other /= Void external "built_in" ensure -- from ANY shallow_implies_deep: standard_is_equal (other) implies Result same_type: Result implies same_type (other) symmetric: Result implies other.is_deep_equal (Current) end is_equal (other: like Current): BOOLEAN -- Is content of string identical to content of string other? require -- from ANY other_not_void: other /= Void do Result := item.is_equal (other.item) ensure -- from ANY symmetric: Result implies other ~ Current consistent: standard_is_equal (other) implies Result end frozen standard_equal (a: detachable ANY; b: like arg #1): BOOLEAN -- Are a and b either both void or attached to -- field-by-field identical objects of the same type? -- Always uses default object comparison criterion. -- (from ANY) do if a = Void then Result := b = Void else Result := b /= Void and then a.standard_is_equal (b) end ensure -- from ANY instance_free: class definition: Result = (a = Void and b = Void) or else ((a /= Void and b /= Void) and then a.standard_is_equal (b)) end frozen standard_is_equal alias "≜" (other: NATIVE_STRING): BOOLEAN -- Is other attached to an object of the same type -- as current object, and field-by-field identical to it? -- (from ANY) require -- from ANY other_not_void: other /= Void external "built_in" ensure -- from ANY same_type: Result implies same_type (other) symmetric: Result implies other.standard_is_equal (Current) end feature -- Status report conforms_to (other: ANY): BOOLEAN -- Does type of current object conform to type -- of other (as per Eiffel: The Language, chapter 13)? -- (from ANY) require -- from ANY other_not_void: other /= Void external "built_in" end same_type (other: ANY): BOOLEAN -- Is type of current object identical to type of other? -- (from ANY) require -- from ANY other_not_void: other /= Void external "built_in" ensure -- from ANY definition: Result = (conforms_to (other) and other.conforms_to (Current)) end feature -- Element change set_shared_from_pointer (a_ptr: POINTER) -- New instance sharing a_ptr. require a_ptr_not_null: a_ptr /= default_pointer do set_shared_from_pointer_and_count (a_ptr, pointer_length_in_bytes (a_ptr)) end set_shared_from_pointer_and_count (a_ptr: POINTER; a_length: INTEGER_32) -- New instance sharing a_ptr of a_length byte. Space for an additional -- null terminating code unit is added to managed_data. require a_ptr_not_null: a_ptr /= default_pointer a_length_non_negative: a_length >= 0 a_length_valid: (a_length \\ unit_size) = 0 do unit_count := a_length // unit_size if not managed_data.is_shared then create managed_data.share_from_pointer (a_ptr, a_length + unit_size) else managed_data.set_from_pointer (a_ptr, a_length + unit_size) end end set_string (a_string: READABLE_STRING_GENERAL) -- Set string with a_string treated as a sequence of Unicode characters. require a_string_not_void: a_string /= Void do set_substring (a_string, 1, a_string.count) end set_substring (a_string: READABLE_STRING_GENERAL; start_pos, end_pos: INTEGER_32) -- Set string with a subset of a_string from a_start_pos index to end_pos index. require a_string_not_void: a_string /= Void start_position_big_enough: start_pos >= 1 end_position_big_enough: start_pos <= end_pos + 1 end_pos_small_enough: end_pos <= a_string.count local u: UTF_CONVERTER do if {PLATFORM}.is_windows then u.escaped_utf_32_substring_into_utf_16_0_pointer (a_string, start_pos, end_pos, managed_data, 0, Upper_cell) else u.escaped_utf_32_substring_into_utf_8_0_pointer (a_string, start_pos, end_pos, managed_data, 0, Upper_cell) end unit_count := Upper_cell.item // unit_size end feature -- Duplication frozen clone (other: detachable ANY): like other obsolete "Use `twin' instead. [2017-05-31]" -- Void if other is void; otherwise new object -- equal to other -- -- For non-void other, clone calls copy; -- to change copying/cloning semantics, redefine copy. -- (from ANY) do if other /= Void then Result := other.twin end ensure -- from ANY instance_free: class equal: Result ~ other end copy (other: NATIVE_STRING) -- Update current object using fields of object attached -- to other, so as to yield equal objects. -- (from ANY) require -- from ANY other_not_void: other /= Void type_identity: same_type (other) external "built_in" ensure -- from ANY is_equal: Current ~ other end frozen deep_clone (other: detachable ANY): like other obsolete "Use `deep_twin' instead. [2017-05-31]" -- Void if other is void: otherwise, new object structure -- recursively duplicated from the one attached to other -- (from ANY) do if other /= Void then Result := other.deep_twin end ensure -- from ANY instance_free: class deep_equal: deep_equal (other, Result) end frozen deep_copy (other: NATIVE_STRING) -- Effect equivalent to that of: -- copy (other . deep_twin) -- (from ANY) require -- from ANY other_not_void: other /= Void do copy (other.deep_twin) ensure -- from ANY deep_equal: deep_equal (Current, other) end frozen deep_twin: NATIVE_STRING -- New object structure recursively duplicated from Current. -- (from ANY) external "built_in" ensure -- from ANY deep_twin_not_void: Result /= Void deep_equal: deep_equal (Current, Result) end frozen standard_clone (other: detachable ANY): like other obsolete "Use `standard_twin' instead. [2017-05-31]" -- Void if other is void; otherwise new object -- field-by-field identical to other. -- Always uses default copying semantics. -- (from ANY) do if other /= Void then Result := other.standard_twin end ensure -- from ANY instance_free: class equal: standard_equal (Result, other) end frozen standard_copy (other: NATIVE_STRING) -- Copy every field of other onto corresponding field -- of current object. -- (from ANY) require -- from ANY other_not_void: other /= Void type_identity: same_type (other) external "built_in" ensure -- from ANY is_standard_equal: standard_is_equal (other) end frozen standard_twin: NATIVE_STRING -- New object field-by-field identical to other. -- Always uses default copying semantics. -- (from ANY) external "built_in" ensure -- from ANY standard_twin_not_void: Result /= Void equal: standard_equal (Result, Current) end frozen twin: NATIVE_STRING -- New object equal to Current -- twin calls copy; to change copying/twinning semantics, redefine copy. -- (from ANY) external "built_in" ensure -- from ANY twin_not_void: Result /= Void is_equal: Result ~ Current end feature -- Basic operations frozen as_attached: attached NATIVE_STRING obsolete "Remove calls to this feature. [2017-05-31]" -- Attached version of Current. -- (Can be used during transitional period to convert -- non-void-safe classes to void-safe ones.) -- (from ANY) do Result := Current end frozen default: detachable NATIVE_STRING -- Default value of object's type -- (from ANY) do end frozen default_pointer: POINTER -- Default value of type POINTER -- (Avoid the need to write p.default for -- some p of type POINTER.) -- (from ANY) do ensure -- from ANY instance_free: class end default_rescue -- Process exception for routines with no Rescue clause. -- (Default: do nothing.) -- (from ANY) do end frozen do_nothing -- Execute a null action. -- (from ANY) do ensure -- from ANY instance_free: class end feature {NONE} -- Implementation c_pointer_length_in_bytes (a_ptr: POINTER): NATURAL_64 -- Length in bytes of a platform specific file name pointer, not -- including the null-terminating character. -- (from NATIVE_STRING_HANDLER) require -- from NATIVE_STRING_HANDLER a_ptr_not_null: a_ptr /= default_pointer external "C inline use %"eif_eiffel.h%"" alias "{ #ifdef EIF_WINDOWS return (EIF_NATURAL_64) wcslen($a_ptr) * sizeof(wchar_t); #else return (EIF_NATURAL_64) strlen($a_ptr) * sizeof(char); #endif }" end Platform: PLATFORM -- Access underlying platform info, used to satisfy invariant below. once create Result end Upper_cell: CELL [INTEGER_32] -- Temporary storage for byte index of last insertions when using UTF_CONVERTER routines. once create Result.put (0) end feature -- Output Io: STD_FILES -- Handle to standard file setup -- (from ANY) once create Result; Result.set_output_default ensure -- from ANY instance_free: class io_not_void: Result /= Void end out: STRING_8 -- New string containing terse printable representation -- of current object -- (from ANY) do Result := tagged_out ensure -- from ANY out_not_void: Result /= Void end print (o: detachable ANY) -- Write terse external representation of o -- on standard output. -- (from ANY) local s: READABLE_STRING_8 do if attached o then s := o.out if attached {READABLE_STRING_32} s as s32 then Io.put_string_32 (s32) elseif attached {READABLE_STRING_8} s as s8 then Io.put_string (s8) else Io.put_string_32 (s.as_string_32) end end ensure -- from ANY instance_free: class end frozen tagged_out: STRING_8 -- New string containing terse printable representation -- of current object -- (from ANY) external "built_in" ensure -- from ANY tagged_out_not_void: Result /= Void end feature -- Platform Operating_environment: OPERATING_ENVIRONMENT -- Objects available from the operating system -- (from ANY) once create Result ensure -- from ANY instance_free: class operating_environment_not_void: Result /= Void end feature {NONE} -- Retrieval frozen internal_correct_mismatch -- Called from runtime to perform a proper dynamic dispatch on correct_mismatch -- from MISMATCH_CORRECTOR. -- (from ANY) local l_msg: STRING_32 l_exc: EXCEPTIONS do if attached {MISMATCH_CORRECTOR} Current as l_corrector then l_corrector.correct_mismatch else create l_msg.make_from_string ("Mismatch: ".as_string_32) create l_exc; l_msg.append (generating_type.name_32); l_exc.raise_retrieval_exception (l_msg) end end feature -- Status Report is_empty: BOOLEAN -- Is current empty? do Result := unit_count = 0 end invariant little_endian_windows: {PLATFORM}.is_windows implies Platform.Is_little_endian even_count_on_windows: {PLATFORM}.is_windows implies managed_data.count \\ unit_size = 0 -- from ANY reflexive_equality: standard_is_equal (Current) reflexive_conformance: conforms_to (Current) note copyright: "Copyright (c) 1984-2020, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software 5949 Hollister Ave., Goleta, CA 93117 USA Telephone 805-685-1006, Fax 805-685-6869 Website http://www.eiffel.com Customer support http://support.eiffel.com ]" end -- class NATIVE_STRING
Generated by ISE EiffelStudio