note description: "[ Objects representing a path, i.e. a way to identify a file or a directory for the current underlying platform. A path is made of two components: 1 - an optional root which can either be: a - a drive letter followed by colon on Windows, i.e. "C:" or "C:\" b - "/" for UNIX root directory. c - "\" for Windows root directory. d - "\\server\share" or "\\server\share\" for Microsoft UNC path. 2 - a sequence of zero or more names. A path is absolute if it has a root, and on windows if the root is a drive, then it should be followed by "\". Otherwise a path is relative. Validity ======== The current class will not check the validity of filenames. Check your file system for your operating system manual for the list of invalid characters. Windows consideration ===================== When the root of a Windows path is a drive, be aware of the following behavior: 1 - "C:filename.txt" refers to the file name "filename.txt" in the current directory on drive "C:". 2 - "C:sub\filename.txt" refers to the file name "filename.txt" in a subdirectory "sub" of the current directory on drive "C:". 3 - "C:\sub\filename.txt" refers to the file name "filename.txt" in a subdirectory "sub" located at the root of the drive "C:". Both forward and backslashes are accepted, but forward slashes are internally converted to backward slashes whenever they are used to construct a path. On Windows, there is a limit of 259 characters for a path. If you need to create a larger path, you can do so by using the following conventions which will let you have paths of about 32,767 characters: 1 - Use \\?\ for non-UNC path and let the rest unchanged. 2 - Use \\?\UNC\server\share for UNC path and let the rest unchanged. The above path cannot be used to specify a relative path. To know more about Windows paths, read the "Naming Files, Paths, and Namespaces" document located at: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx Unicode consideration ===================== The PATH class treats strings as sequence of Unicode characters, i.e. an instance of a READABLE_STRING_8 or descendant will be treated as if characters in the range 128 .. 255 were Unicode code points. This contrasts to the FILE/DIRECTORY classes where to preserve backward compatibility, those characters are treated as is. Mixed-encoding consideration ============================ Most operating systems have conventions for paths that are incompatible with Unicode. On UNIX, in a sequence of names, each name is just a null-terminated byte sequence, it does not follow any specific encoding. Usually the locale setting enables you to see the filename 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 filename is not directly representable as a Unicode string. To make it possible to create and store paths in a textually representable form, the query name will create an encoded representation that can be then later used in make_from_string to create a PATH equivalent to the original path. 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). Immutability ============ Instances of the current class are immutable. ]" library: "Free implementation of ELKS library" status: "See notice at end of class." date: "$Date: 2020-05-19 14:32:38 +0000 (Tue, 19 May 2020) $" revision: "$Revision: 104260 $" class interface PATH create {NATIVE_STRING_HANDLER} make_from_pointer (a_path_pointer: POINTER) -- Initialize current from a_path_pointer, a platform system specific encoding of -- a path that is null-terminated. require a_path_pointer_not_null: a_path_pointer /= default_pointer create {PATH} make_from_storage (a_path: STRING_8) -- Initialize current from a_path and normalize a_path as it may be coming -- from a user provided string or from a C API. require a_path_not_void: a_path /= Void ensure shared: storage = a_path is_normalized: is_normalized make_from_normalized_storage (a_path: STRING_8) -- Initialize current from a_path which has already been normalized. require a_path_not_void: a_path /= Void ensure shared: storage = a_path is_normalized: is_normalized create make_empty -- Initialize current as an empty path. ensure is_empty: is_empty is_normalized: is_normalized make_current -- Initialize current as the symbolic representation of the current working directory ensure not_empty: not is_empty is_normalized: is_normalized is_current: is_current_symbol make_from_string (a_path: READABLE_STRING_GENERAL) -- Initialize current from a_path treated as a sequence of Unicode characters. -- If a_path is trying to represent a mixed-encoded path, then a_path should use -- the escaped representation as described in UTF_CONVERTER. require a_path_not_void: a_path /= Void ensure not_empty: not a_path.is_empty implies not is_empty is_normalized: is_normalized roundtrip: True roundtrip_with_trailing: True make_from_separate (a_path: separate PATH) -- Initialize from separate a_path. require a_path_not_void: a_path /= Void ensure not_empty: not a_path.is_empty implies not is_empty is_normalized: is_normalized feature -- Access absolute_path: PATH -- Absolute path of Current. -- If Current is already absolute, then return Current. -- If Current is empty, then return the current working directory. -- Otherwise resolve the path in a platform specific way: -- * On UNIX, resolve against the current working directory -- * On Windows: -- a) if current has a drive letter which is not followed by "\" -- resolve against the current working directory for that drive letter, -- otherwise resolve against the current working directory. -- b) if current path starts with "\", not a double "\\", then resolve -- against the root of the current working directory (i.e. a drive -- letter "C:\" or a UNC path "\\server\share\".) absolute_path_in (a_current_directory: PATH): PATH -- Absolute path of Current in the context of a_current_directory. -- If Current is already absolute, then return Current. -- If Current is empty, then return a_current_directory. -- Otherwise resolve the path in a platform specific way: -- * On UNIX, resolve against a_current_directory -- * On Windows: -- a) if current has a drive letter which is not followed by "\" -- resolve against a_current_directory for that drive letter, -- otherwise resolve against a_current_directory. -- b) if current path starts with "\", not a double "\\", then resolve -- against the root of `a_current_directory; (i.e. a drive -- letter "C:\" or a UNC path "\\server\share\".) require a_current_directory_not_void: a_current_directory /= Void a_current_directory_absolute: a_current_directory.is_absolute ensure has_root: Result.has_root canonical_path: PATH -- Canonical path of Current. -- Similar to absolute_path except that sequences containing "." or ".." are -- resolved. components: ARRAYED_LIST [PATH] -- Sequence of simple paths making up Current, including root if any. directory_separator: CHARACTER_8 -- Default directory separator for the current platform. entry: detachable PATH -- Name of file or directory denoted by Current if any. -- This is the last name in the current sequence. ensure not_empty: Result /= Void implies not Result.is_empty extension: detachable IMMUTABLE_STRING_32 -- Extension if any of current entry. ensure not_empty: attached Result implies not Result.is_empty no_dot: attached Result implies not Result.has ('.'.to_character_32) generating_type: TYPE [detachable PATH] -- Type of current object -- (type of which it is a direct instance) -- (from ANY) ensure -- from ANY generating_type_not_void: Result /= Void generator: STRING_8 -- Name of current object's generating class -- (base class of the type of which it is a direct instance) -- (from ANY) ensure -- from ANY generator_not_void: Result /= Void generator_not_empty: not Result.is_empty hash_code: INTEGER_32 -- Hash code value ensure -- from HASHABLE good_hash_value: Result >= 0 native_string: NATIVE_STRING -- Convert current into an instance of NATIVE_STRING ensure set: Result.raw_string.same_string (storage) parent: PATH -- Parent directory if any, otherwise current working path. -- The parent of a path consists of root if any, and of each -- simple names in the current sequence except for the last. root: detachable PATH -- Root if any of current path. ensure has_root_implies_not_void: has_root implies Result /= Void Unix_separator: CHARACTER_8 = '/' Windows_separator: CHARACTER_8 = '\' -- Platform specific directory separator. 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) 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) 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) 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)) is_case_insensitive_equal (other: PATH): BOOLEAN -- Compare path without paying attention to case. If the path is containing some mixed-encoding -- we might ignore many characters when doing the case comparison. require other_not_void: other /= Void is_case_sensitive_equal (other: PATH): BOOLEAN -- Compare path and paying attention to case. require other_not_void: other /= Void frozen is_deep_equal alias "≡≡≡" (other: PATH): BOOLEAN -- Are Current and other attached to isomorphic object structures? -- (from ANY) require -- from ANY other_not_void: other /= Void 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) is_equal (other: like Current): BOOLEAN -- Is other attached to an object considered -- equal to current object? require -- from ANY other_not_void: other /= Void ensure -- from ANY symmetric: Result implies other ~ Current consistent: standard_is_equal (other) implies Result ensure then -- from COMPARABLE trichotomy: Result = (not (Current < other) and not (other < Current)) is_greater alias ">" (other: PATH): BOOLEAN -- Is current object greater than other? -- (from COMPARABLE) require -- from PART_COMPARABLE other_exists: other /= Void ensure then -- from COMPARABLE definition: Result = (other < Current) is_greater_equal alias ">=" alias "≥" (other: PATH): BOOLEAN -- Is current object greater than or equal to other? -- (from COMPARABLE) require -- from PART_COMPARABLE other_exists: other /= Void ensure then -- from COMPARABLE definition: Result = (other <= Current) is_less alias "<" (other: like Current): BOOLEAN -- Is current object less than other? require -- from PART_COMPARABLE other_exists: other /= Void ensure then -- from COMPARABLE asymmetric: Result implies not (other < Current) is_less_equal alias "<=" alias "≤" (other: PATH): BOOLEAN -- Is current object less than or equal to other? -- (from COMPARABLE) require -- from PART_COMPARABLE other_exists: other /= Void ensure then -- from COMPARABLE definition: Result = ((Current < other) or (Current ~ other)) max alias "∨" (other: PATH): PATH -- The greater of current object and other -- (from COMPARABLE) require -- from COMPARABLE other_exists: other /= Void ensure -- from COMPARABLE current_if_not_smaller: Current >= other implies Result = Current other_if_smaller: Current < other implies Result = other min alias "∧" (other: PATH): PATH -- The smaller of current object and other -- (from COMPARABLE) require -- from COMPARABLE other_exists: other /= Void ensure -- from COMPARABLE current_if_not_greater: Current <= other implies Result = Current other_if_greater: Current > other implies Result = other same_as (other: detachable PATH): BOOLEAN -- Is Current the same path as other? -- Note that no canonicalization is being performed to compare paths, -- paths are compared using the OS-specific convention for letter case. 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) 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)) frozen standard_is_equal alias "≜" (other: PATH): 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 ensure -- from ANY same_type: Result implies same_type (other) symmetric: Result implies other.standard_is_equal (Current) three_way_comparison alias "⋚" (other: PATH): INTEGER_32 -- If current object equal to other, 0; -- if smaller, -1; if greater, 1 -- (from COMPARABLE) require -- from COMPARABLE other_exists: other /= Void ensure -- from COMPARABLE equal_zero: (Result = 0) = (Current ~ other) smaller_negative: (Result = -1) = (Current < other) greater_positive: (Result = 1) = (Current > other) 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 has_extension (a_ext: READABLE_STRING_GENERAL): BOOLEAN -- Does Current has an extension a_ext compared in a case insensitive manner? require a_ext_not_void: a_ext /= Void a_ext_not_empty: not a_ext.is_empty a_ext_has_no_dot: not a_ext.has ('.'.to_character_32) has_root: BOOLEAN -- Does current have a root? ensure defintion: Result implies not is_empty is_absolute: BOOLEAN -- Is current path absolute? is_current_symbol: BOOLEAN -- Is Current a representation of "."? is_empty: BOOLEAN -- Is current empty, i.e. no root and no sequence of names? is_hashable: BOOLEAN -- May current object be hashed? -- (True by default.) -- (from HASHABLE) is_parent_symbol: BOOLEAN -- Is Current Representation of ".."? is_relative: BOOLEAN -- Is current path relative? is_same_file_as (a_path: PATH): BOOLEAN -- Does Current and a_path points to the same file on disk? It is different from path equality -- as it will take into account symbolic links. -- If Current or/and a_path do not exists, it will yield false, otherwise it will compare -- the file at the file system level. require a_path_not_void: a_path /= Void is_simple: BOOLEAN -- Is current path made of only one name and no root? -- I.e. readme.txt, usr or the empty path. 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 ensure -- from ANY definition: Result = (conforms_to (other) and other.conforms_to (Current)) feature -- Status setting appended (a_extra: READABLE_STRING_GENERAL): PATH -- New path instance of current where entry is appended with a_extra without -- adding a directory separator. -- For example if Current path is "C:" and a_path is "path\file.txt", it will yield -- "C:path\file.txt". -- Note that a_extra can be an encoding of a mixed-encoding simple name and it will -- be decoded accordingly (see note clause for the class for more details.) require a_extra_not_void: a_extra /= Void a_extra_not_empty: not a_extra.is_empty ensure not_empty: not Result.is_empty appended: Result.name.same_string (name + (create {PATH}.make_from_string (a_extra)).name) appended_with_extension (a_ext: READABLE_STRING_GENERAL): PATH -- New path instance of current where entry is extended with a dot followed by a_ext. -- If Current already has a dot, no dot is added. -- Note that a_ext can be an encoding of a mixed-encoding simple name and it will -- be decoded accordingly (see note clause for the class for more details.) require a_ext_not_void: a_ext /= Void a_ext_not_empty: not a_ext.is_empty a_ext_has_no_dot: not a_ext.has ('.'.to_character_32) a_ext_has_no_directory_separator: not a_ext.has (Windows_separator.to_character_32) and not a_ext.has (Unix_separator.to_character_32) has_entry: entry /= Void ensure not_empty: not Result.is_empty extension_set: attached Result.extension as l_ext and then l_ext.same_string_general (a_ext) components_stable: Result.components.count = components.count extended (a_name: READABLE_STRING_GENERAL): PATH -- New path instance of current extended with path a_name. -- If current is not empty, then a_name cannot have a root. -- A directory separator is added between two entries except -- 1 - a_name starts with a directory separator (i.e. it has a root) -- 2 - if current is empty or is just a root. -- Note that a_name can be an encoding of a mixed-encoding simple name and it will -- be decoded accordingly (see note clause for the class for more details.) require a_name_not_void: a_name /= Void a_name_not_empty: not a_name.is_empty a_name_has_no_root: not is_empty implies not (create {PATH}.make_from_string (a_name)).has_root ensure associated_path_of_name: attached (create {PATH}.make_from_string (a_name)) as l_path not_empty: not Result.is_empty extended_with_only_empty_or_root: (same_as (root) or is_empty) implies Result.name.same_string (name + l_path.name) extended_with_more_than_root_or_not_empty: (not same_as (root) and not is_empty) implies Result.name.same_string (name + Directory_separator_string + l_path.name) extended_path alias "+" (a_path: PATH): PATH -- New path instance of current extended with path a_path. -- If current is not empty, then a_path cannot have a root. -- A directory separator is added between two entries except -- 1 - a_path starts with a directory separator (i.e. it has a root) -- 2 - if current is empty or is just a root. require a_path_not_void: a_path /= Void a_path_not_empty: not a_path.is_empty a_path_has_no_root: not is_empty implies not a_path.has_root ensure not_empty: not Result.is_empty extended_with_only_empty_or_root: (same_as (root) or is_empty) implies Result.name.same_string (name + a_path.name) extended_with_more_than_root_or_not_empty: (not same_as (root) and not is_empty) implies Result.name.same_string (name + Directory_separator_string + a_path.name) feature -- Duplication copy (other: like Current) -- Update current object using fields of object attached -- to other, so as to yield equal objects. require -- from ANY other_not_void: other /= Void type_identity: same_type (other) ensure -- from ANY is_equal: Current ~ other frozen deep_copy (other: PATH) -- Effect equivalent to that of: -- copy (other . deep_twin) -- (from ANY) require -- from ANY other_not_void: other /= Void ensure -- from ANY deep_equal: deep_equal (Current, other) frozen deep_twin: PATH -- New object structure recursively duplicated from Current. -- (from ANY) ensure -- from ANY deep_twin_not_void: Result /= Void deep_equal: deep_equal (Current, Result) frozen standard_copy (other: PATH) -- 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) ensure -- from ANY is_standard_equal: standard_is_equal (other) frozen standard_twin: PATH -- New object field-by-field identical to other. -- Always uses default copying semantics. -- (from ANY) ensure -- from ANY standard_twin_not_void: Result /= Void equal: standard_equal (Result, Current) frozen twin: PATH -- New object equal to Current -- twin calls copy; to change copying/twinning semantics, redefine copy. -- (from ANY) ensure -- from ANY twin_not_void: Result /= Void is_equal: Result ~ Current feature -- Basic operations frozen default: detachable PATH -- Default value of object's type -- (from ANY) frozen default_pointer: POINTER -- Default value of type POINTER -- (Avoid the need to write p.default for -- some p of type POINTER.) -- (from ANY) ensure -- from ANY instance_free: class default_rescue -- Process exception for routines with no Rescue clause. -- (Default: do nothing.) -- (from ANY) frozen do_nothing -- Execute a null action. -- (from ANY) ensure -- from ANY instance_free: class feature -- Output debug_output: READABLE_STRING_32 -- String that should be displayed in debugger to represent Current. ensure -- from DEBUG_OUTPUT result_not_void: Result /= Void Io: STD_FILES -- Handle to standard file setup -- (from ANY) ensure -- from ANY instance_free: class io_not_void: Result /= Void name: IMMUTABLE_STRING_32 -- If current is representable in Unicode, the Unicode representation. -- Otherwise all non-valid sequences for the current platform in the path are escaped -- as mentioned in the note clause of the class. -- To ensure roundtrip, you cannot use name directly to create a FILE, you have to -- create a PATH instance using make_from_string before passing it to the creation -- procedure of FILE taking an instance of PATH. ensure roundtrip: same_as (create {PATH}.make_from_string (Result)) out: STRING_8 -- Unicode representation of the underlying filename if representable, -- otherwise a UTF-8 encoded version. -- Use utf_8_name to have a printable representation whose format is not going -- to be changed in the future. ensure -- from ANY out_not_void: Result /= Void print (o: detachable ANY) -- Write terse external representation of o -- on standard output. -- (from ANY) ensure -- from ANY instance_free: class frozen tagged_out: STRING_8 -- New string containing terse printable representation -- of current object -- (from ANY) ensure -- from ANY tagged_out_not_void: Result /= Void utf_8_name: STRING_8 -- UTF-8 representation of the underlying filename. feature -- Platform Operating_environment: OPERATING_ENVIRONMENT -- Objects available from the operating system -- (from ANY) ensure -- from ANY instance_free: class operating_environment_not_void: Result /= Void invariant little_endian_windows: {PLATFORM}.is_windows implies Platform.Is_little_endian even_count_on_windows: {PLATFORM}.is_windows implies storage.count \\ unit_size = 0 no_forward_slash_on_windows: {PLATFORM}.is_windows implies not storage.has_substring ("/%U") -- from ANY reflexive_equality: standard_is_equal (Current) reflexive_conformance: conforms_to (Current) -- from COMPARABLE irreflexive_comparison: not (Current < 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 PATH
Generated by ISE EiffelStudio