PageRenderTime 22ms CodeModel.GetById 13ms app.highlight 4ms RepoModel.GetById 1ms app.codeStats 0ms

/src/lib/io/filesystem/path_name.e

http://github.com/tybor/Liberty
Specman e | 415 lines | 290 code | 41 blank | 84 comment | 9 complexity | d569fad87d579f0d4ffd8d5d5feb96ff MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4deferred class PATH_NAME
  5   -- Operating system path name
  6
  7inherit
  8   PATH_JOINER
  9
 10feature {ANY} -- Creation/ Initialization
 11   make_empty
 12         -- Make a 'null' path
 13      deferred
 14      ensure
 15         is_empty
 16      end
 17
 18   make_root
 19         -- Path to root directory (in current drive)
 20      deferred
 21      ensure
 22         is_absolute
 23      end
 24
 25   make_current
 26         -- Path to current directory (relative). See also `to_absolute'
 27         -- if you need the absolute current working directory
 28      deferred
 29      ensure
 30         not is_absolute
 31      end
 32
 33   make_from_string (s: STRING)
 34      require
 35         s /= Void
 36         s.is_empty or else is_valid_path(s)
 37      deferred
 38      ensure
 39         to_string.is_equal(s)
 40         (old to_string /= s) implies to_string /= s
 41      end
 42
 43   make_from_path_name (pn: PATH_NAME)
 44      require
 45         pn /= Void
 46      do
 47         make_empty
 48         pn.join_to(Current)
 49      end
 50
 51feature {ANY} -- Constants
 52   extension_separator: CHARACTER
 53         -- Character used to separate filenames from extensions
 54      deferred
 55      end
 56
 57   directory_separator: CHARACTER
 58         -- Character used to separate directories
 59         -- This character is forbidden in filenames
 60      deferred
 61      end
 62
 63feature {ANY} -- Access
 64   to_string: STRING
 65         -- String representation
 66      deferred
 67      ensure
 68         Result /= Void
 69         Result.is_empty or else is_valid_path(Result)
 70      end
 71
 72   drive_specification: STRING
 73         -- Drive specified by the current path, Void if none
 74      deferred
 75      ensure
 76         Result /= Void implies to_string.has_prefix(Result)
 77      end
 78
 79   count: INTEGER
 80         -- Number of elements in_path
 81      deferred
 82      ensure
 83         Result >= 0
 84      end
 85
 86   is_empty: BOOLEAN
 87         -- Path is null. Note that you can have a null absolute path
 88         -- (i.e., root) or a null relative path (current directory)
 89      do
 90         Result := count = 0
 91      ensure
 92         Result = (count = 0)
 93      end
 94
 95   last: STRING
 96         -- Last component (also known as "basename")
 97      require
 98         not is_empty
 99      deferred
100      ensure
101         Result /= Void
102         is_valid_file_name(Result)
103      end
104
105   extension: STRING
106         -- Path extension (may be empty)
107      deferred
108      ensure
109         is_suffix: to_string.has_suffix(Result)
110         is_extension: not Result.is_empty implies Result.first = extension_separator
111         is_minimal: Result.occurrences(extension_separator) <= 1
112         not Result.has(directory_separator)
113         is_empty implies Result.is_empty
114      end
115
116   is_absolute: BOOLEAN
117         -- absolute path?
118      deferred
119      end
120
121   as_absolute: like Current
122         -- Equivalent absolute path
123      do
124         Result := twin
125         Result.to_absolute
126      ensure
127         Result.is_absolute
128         Result.is_normalized
129      end
130
131   is_normalized: BOOLEAN
132         -- Has no redundant separators, or redundant up-references
133      deferred
134      end
135
136   is_valid_path (path: STRING): BOOLEAN
137         -- Does `path' represent a syntactically valid file or
138         -- directory path? The result does not imply that there
139         -- actually a file or directory with that name. This
140         -- operation does not perform any disk access.
141      require
142         path /= Void
143      deferred
144      ensure
145         path.is_equal(old path.twin)
146      end
147
148   is_valid_file_name (name: STRING): BOOLEAN
149         -- Does `path' only contain valid characters for a file? The
150         -- result does not imply that there is actually a file or
151         -- directory with that name. Not the same as `is_valid_path':
152         -- path separators (/ for unix, \ for windows, ...) are
153         -- allowed in paths, but not in file names. This operation
154         -- does not perform any disk access.
155      require
156         name /= Void
157      deferred
158      ensure
159         name.is_equal(old name.twin)
160      end
161
162   is_valid_directory: BOOLEAN
163         -- Does `Current' represent a syntactically valid directory
164         -- path? For many Systems, there may be no syntactical
165         -- difference between file paths and directory paths, in
166         -- that case `is_valid_directory' is always True.
167      deferred
168      ensure
169         Result or is_valid_file
170      end
171
172   is_valid_file: BOOLEAN
173         -- Does `Current' represent a syntactically valid directory
174         -- path? For many Systems, there may be no syntactical
175         -- difference between file paths and directory paths, in
176         -- that case `is_valid_file' is always True.
177      deferred
178      ensure
179         Result or is_valid_directory
180      end
181
182   is_file: BOOLEAN
183         -- Path points to an existing regular file?
184      do
185         Result := (create {FILE_TOOLS}).is_file(to_string)
186      end
187
188   is_directory: BOOLEAN
189         -- Path points to an existing directory?
190      do
191         Result := (create {FILE_TOOLS}).is_directory(to_string)
192      end
193
194   infix "+" (other: like Current): like Current
195         -- Join with `other' using filesystem semantics
196      require
197         other /= Void
198      do
199         Result := twin
200         Result.join(other)
201      ensure
202      -- Result is a fresh instance
203      end
204
205   infix "/" (elem: STRING): like Current
206         -- Path with `elem' inside current
207      require
208         elem /= Void
209         not elem.has(directory_separator)
210      do
211         Result := twin
212         Result.add_last(elem)
213      ensure
214      -- Result is a fresh instance
215         Result.is_empty = (is_empty and elem.is_empty)
216         Result.last.is_equal(elem)
217      end
218
219   short_name: STRING
220      deferred
221      ensure
222         Result /= Void
223      end
224
225feature {ANY} -- Operations
226   to_absolute
227         -- Transform into equivalent absolute path
228      deferred
229      ensure
230         is_absolute
231         is_normalized
232      end
233
234   normalize_case
235         -- Transform into normalized case version (equivalent), with
236         -- standard path separators
237      deferred
238      end
239
240   normalize
241         -- Normalize removing double separators, and up-references
242      deferred
243      ensure
244         is_normalized
245         old is_normalized implies to_string.is_equal(old to_string.twin)
246      end
247
248   remove_last
249         -- Remove last component of path (keep the "dirname")
250      require
251         not is_empty
252      deferred
253      ensure
254      -- (old twin).is_equal (Current / (old last))
255      -- assertion above commented because of SE bug
256         count = old count - 1
257      end
258
259   go_up
260         -- Go up by one directory
261      deferred
262      end
263
264   add_last (elem: STRING)
265      require
266         elem /= Void
267         not elem.has(directory_separator)
268      deferred
269      ensure
270         last.is_equal(elem)
271         not_reduced: old count <= count
272         may_grow_one: count <= old count + 1
273      end
274
275   join (other: PATH_NAME)
276         -- Join with `other' using filesystem semantics
277      require
278         other /= Void
279      do
280         other.join_to(Current)
281      ensure
282         (old is_normalized) implies is_normalized
283      -- definition: to_string.is_equal (old (Current+other).to_string)
284      -- assertion above is commented out because of SE bug
285      end
286
287   join_to (other: PATH_JOINER)
288      require
289         other /= Void
290      deferred
291      end
292
293   expand_user
294         -- Replace an initial "~" or "~user" by user home directory
295      deferred
296      ensure
297         not (old to_string.twin).has_prefix(once "~") implies to_string.is_equal(old to_string.twin)
298      end
299
300   expand_variables
301         -- Replace substrings of form $name or ${name} with environment
302         -- variable values
303      local
304         p, len: INTEGER; new, varname, subst: STRING; sys: SYSTEM
305      do
306         new := once ""
307         varname := once ""
308         subst := once ""
309         len := to_string.count
310         from
311            p := 1
312            new.clear_count
313            varname.clear_count
314         until
315            p > len
316         loop
317            if to_string.item(p) = '$' then
318               varname.clear_count
319               subst.clear_count
320               subst.extend('$')
321               p := p + 1
322               if p = len then
323               elseif to_string.item(p) = '{' then
324                  -- ${var}
325                  subst.extend('{')
326                  from
327                     p := p + 1
328                  until
329                     p > len or else to_string.item(p) = '}'
330                  loop
331                     varname.extend(to_string.item(p))
332                     subst.extend(to_string.item(p))
333                     p := p + 1
334                  end
335                  if p <= len then
336                     p := p + 1 -- skip '}'
337                     subst.extend('}')
338                  else
339                     varname.clear_count
340                     -- invalid variable
341                  end
342               else
343                  -- $var
344                  from
345                  until
346                     p > len or else not to_string.item(p).is_letter_or_digit
347                  loop
348                     varname.extend(to_string.item(p))
349                     subst.extend(to_string.item(p))
350                     p := p + 1
351                  end
352               end
353               if not varname.is_empty and then sys.get_environment_variable(varname) /= Void then
354                  subst.copy(sys.get_environment_variable(varname))
355               end
356               new.append(subst)
357            else
358               new.extend(to_string.item(p))
359               p := p + 1
360            end
361         end
362         to_string.copy(new)
363      ensure
364         not (old to_string.twin).has('$') implies to_string.is_equal(old to_string.twin)
365      end
366
367   expand_shellouts
368         -- Replace substrings of form $(command) with execution of
369         -- shell commands
370      deferred
371      ensure
372         not to_string.has_substring("$(") implies to_string.is_equal(old to_string.twin)
373      end
374
375feature {PATH_JOINER}
376   join_up
377      do
378         go_up
379      end
380
381   end_join
382      do
383         if is_empty and then not is_absolute then
384            make_current
385         end
386      end
387
388feature {}
389   tmp: like Current
390      deferred
391      ensure
392         Result /= Void
393      end
394
395end -- class PATH_NAME
396--
397-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
398--
399-- Permission is hereby granted, free of charge, to any person obtaining a copy
400-- of this software and associated documentation files (the "Software"), to deal
401-- in the Software without restriction, including without limitation the rights
402-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
403-- copies of the Software, and to permit persons to whom the Software is
404-- furnished to do so, subject to the following conditions:
405--
406-- The above copyright notice and this permission notice shall be included in
407-- all copies or substantial portions of the Software.
408--
409-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
410-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
411-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
412-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
413-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
414-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
415-- THE SOFTWARE.