4 /*****************************************************************************\
7 * Author : Chris Koeritz *
9 *******************************************************************************
10 * Copyright (c) 1993-$now By Author. This program is free software; you can *
11 * redistribute it and/or modify it under the terms of the GNU General Public *
12 * License as published by the Free Software Foundation; either version 2 of *
13 * the License or (at your option) any later version. This is online at: *
14 * http://www.fsf.org/copyleft/gpl.html *
15 * Please send any updates to: fred@gruntose.com *
16 \*****************************************************************************/
18 #include <basis/astring.h>
19 #include <basis/byte_array.h>
20 #include <basis/contracts.h>
21 #include <structures/string_array.h>
23 // forward declarations.
26 //hmmm: this doesn't really belong here, does it...
27 // define useful constant for filesystem path length.
31 #define MAX_ABS_PATH MAX_PATH
34 #include <sys/syslimits.h>
38 #define MAX_ABS_PATH PATH_MAX
43 namespace filesystem {
45 //! Provides operations commonly needed on file names.
47 class filename : public basis::astring, public virtual basis::packable
50 filename(); //!< blank constructor.
51 filename(const basis::astring &name);
52 //!< creates a filename from any part of a full pathname, if possible.
53 /*!< if the name contains quotes, they are stripped out. */
54 filename(const basis::astring &directory, const basis::astring &name_of_file);
55 //!< constructs a filename from a "directory" and the "name_of_file".
56 /*!< the "name_of_file" can itself be a directory. */
57 filename(const filename &to_copy); //!< copy constructor.
62 //!< returns true if the filename seems to be valid.
63 /*!< this means that not only was the pathname parsed and found valid,
64 but the file actually exists. */
66 const basis::astring &raw() const;
67 //!< returns the astring that we're holding onto for the path.
68 basis::astring &raw();
69 //!< accesses the astring that we're holding onto for the path.
70 /*!< important note: if you change the string with this non-const raw()
71 method, you MUST call canonicalize() on it again afterwards. */
73 filename &operator = (const filename &to_copy);
74 //!< provides assignment for this object, plus a simple string.
75 filename &operator = (const basis::astring &to_copy);
76 //!< provides assignment for this object, plus a simple string.
77 /*!< the latter version invokes canonicalize to clean the string up. */
80 //!< cleans up the filename as needed for the current operating system.
81 /*!< reforms the name by replacing any alternate directory separators with
82 the operating system's preferred character. */
85 //!< returns true if the file exists.
88 //!< actually removes the file, if possible.
89 /*!< if the file was successfully deleted, then true is returned. */
91 filename parent() const;
92 //!< returns the parent filename for this one.
95 //!< removes the deepest component of the pathname.
96 /*!< the component might be a file or directory name, but popping beyond
97 the top-level directory will not succeed. the returned string contains
98 the component that was removed. it will be a blank string if nothing
101 void push(const basis::astring &to_push);
102 //!< pushes a new filename onto the current pathname.
103 /*!< this only makes sense as a real pathname if this is currently a
104 directory name and the component "to_push" is a child of that directory
105 (or one intends to create that component as a child). this is the
108 filename basename() const;
109 //!< returns the base of the filename; no directory.
110 filename dirname() const;
111 //!< returns the directory for the filename.
112 /*!< if no directory name can be found in the filename, then "." is
114 basis::astring dirname(bool add_slash) const;
115 //!< returns the directory for the filename and optionally adds a slash.
116 /*!< if "add_slash" is true, then the default directory separator will be
117 present on the end of the string. */
118 bool had_directory() const { return _had_directory; }
119 //!< returns true if the name that we were given had a non-empty directory.
120 /*!< this allows one to distinguish between a file with the current
121 directory (.) attached and a file with no directory specified. */
123 char drive(bool interact_with_fs = false) const;
124 //!< returns the drive letter for the file, without the colon.
125 /*!< this only makes sense for a fully qualified MS-DOS style name. if no
126 drive letter is found, then '\0' is returned. if "interact_with_fs" is
127 true, then the file system will be checked for the actual drive if no
128 drive letter was found in the contents. */
130 basis::astring extension() const;
131 //!< returns the extension for the file, if one is present.
133 basis::astring rootname() const;
134 //!< returns the root part of the basename without an extension.
136 // status functions return true if the characteristic embodied in
137 // the name is also true.
139 bool is_directory() const;
140 bool is_writable() const;
141 bool is_readable() const;
142 bool is_executable() const;
144 // is_normal makes sure that the file or directory is not a named pipe or other
145 // special type of file. symbolic links are considered normal.
146 bool is_normal() const;
150 ALLOW_READ = 0x1, ALLOW_WRITE = 0x2,
151 ALLOW_BOTH = ALLOW_READ | ALLOW_WRITE
154 enum ownership_modes {
156 USER_RIGHTS = 0x1, GROUP_RIGHTS = 0x2, OTHER_RIGHTS = 0x4,
157 ALL_RIGHTS = USER_RIGHTS | GROUP_RIGHTS | OTHER_RIGHTS
160 bool chmod(int write_mode, int owner_mode) const;
161 //!< changes the access rights on the file.
163 //! the default separator for directories per operating system.
164 /*! the PC uses the backward slash to separate file and directory names from
165 each other, while Unix uses the forward slash. */
166 enum directory_separator { pc_separator = '\\', unix_separator = '/' };
168 static bool separator(char is_it);
169 //!< returns true if the character "is_it" in question is a separator.
171 static basis::astring default_separator();
172 //!< returns the default separator character for this OS.
174 static bool legal_character(char to_check);
175 //!< returns true if "to_check" is a valid character in a filename.
176 /*!< this does not consider separator characters; it only looks at the
177 the name components. also, it is appropriate for the union of the
178 operating systems we support. */
180 static void detooth_filename(basis::astring &to_clean, char replacement = '_');
181 //!< takes any known illegal file system characters out of "to_clean".
182 /*!< this prepares "to_clean" for use as a component in a larger filename
183 by ensuring that the file system will not reject the name (as long as a
184 suitable directory path is prepended to the name and permissions allow
185 the file to be created or accessed). the "replacement" is used as the
186 character that is substituted instead of illegal characters. */
188 void separate(bool &rooted, structures::string_array &pieces) const;
189 //!< breaks the filename into its component parts.
190 /*!< this returns an array containing the component names for the path in
191 this filename object. if the "rooted" flag is set to true, then the path
192 was absolute (i.e. started at '/' in unix. this notion is not needed for
193 dos/windoze, as the first component will be something like 'a:'). */
195 void join(bool rooted, const structures::string_array &pieces);
196 //!< undoes a separate() operation to get the filename back.
197 /*!< "this" is set to a filename made from each of the "pieces". if there
198 are any directory separators inside the pieces themselves, then they will
199 be removed by canonicalize(). if separate() said the path was rooted,
200 then join needs to be told that. */
202 // these implement the packing functionality.
203 virtual void pack(basis::byte_array &packed_form) const;
204 virtual bool unpack(basis::byte_array &packed_form);
205 virtual int packed_size() const;
207 bool compare_prefix(const filename &to_compare, basis::astring &sequel);
208 //!< examines "this" filename to see if it's a prefix of "to_compare".
209 /*!< this returns true if all of "this" is the same as the first portion
210 of "to_compare". that is, if "this" is a prefix of "to_compare", then
211 true is returned. this will always fail if there are fewer components in
212 "to_compare". it will always succeed if the two filenames are identical.
213 on success, the "sequel" is set to the portion of "to_compare" that's
214 not included in this filename. */
216 bool compare_prefix(const filename &to_compare);
217 //!< this simpler form doesn't bother with computing the sequel.
219 bool compare_suffix(const filename &to_compare, basis::astring &prequel);
220 //!< compares the back end of a filename to this.
221 /*!< this is similar to compare_prefix() but it checks to see if the
222 back end of "this" filename is the same as "to_compare". if "this" is
223 longer than "to_compare", then failure occurs. only if all of the bits
224 in "this" are seen in the back of "to_compare" is true returned. */
226 bool compare_suffix(const filename &to_compare);
228 static basis::astring null_device();
229 //!< returns the name for the black hole device that consumes all input, i.e. /dev/null.
232 bool _had_directory; //!< true if _some_ directory was specified on init.
233 /// basis::astring *_contents; //!< the full path is held here.
235 int find_last_separator(const basis::astring &look_at) const;
236 //!< locates the last separator character in the filename.
238 bool get_info(status_info *to_fill) const;
239 //!< returns information for the filename.
241 // helper functions do the real work for comparing.
242 bool base_compare_prefix(const filename &to_compare, structures::string_array &first,
243 structures::string_array &second);
244 bool base_compare_suffix(const filename &to_compare, structures::string_array &first,
245 structures::string_array &second);