first check-in of feisty meow codebase. many things broken still due to recent
[feisty_meow.git] / core / library / filesystem / filename.h
1 #ifndef FILENAME_CLASS
2 #define FILENAME_CLASS
3
4 /*****************************************************************************\
5 *                                                                             *
6 *  Name   : filename                                                          *
7 *  Author : Chris Koeritz                                                     *
8 *                                                                             *
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 \*****************************************************************************/
17
18 #include <basis/astring.h>
19 #include <basis/byte_array.h>
20 #include <basis/contracts.h>
21 #include <structures/string_array.h>
22
23 // forward declarations.
24 class status_info;
25
26 //hmmm: this doesn't really belong here, does it.
27
28 // define useful constant for filesystem path length.
29 #ifndef MAX_ABS_PATH 
30   #ifdef __WIN32__
31     #include <windows.h>
32     #define MAX_ABS_PATH MAX_PATH
33   #else
34     #ifdef __APPLE__
35       #include <sys/syslimits.h>
36     #else
37       #include <limits.h>
38     #endif
39     #define MAX_ABS_PATH PATH_MAX
40   #endif
41 #endif
42
43
44 namespace filesystem {
45
46 //! Provides operations commonly needed on file names.
47
48 class filename : public basis::astring, public virtual basis::packable
49 {
50 public:
51   filename();  //!< blank constructor.
52   filename(const basis::astring &name);
53     //!< creates a filename from any part of a full pathname, if possible.
54     /*!< if the name contains quotes, they are stripped out. */
55   filename(const basis::astring &directory, const basis::astring &name_of_file);
56     //!< constructs a filename from a "directory" and the "name_of_file".
57     /*!< the "name_of_file" can itself be a directory. */
58   filename(const filename &to_copy);  //!< copy constructor.
59
60   virtual ~filename();
61
62   bool good() const;
63     //!< returns true if the filename seems to be valid.
64     /*!< this means that not only was the pathname parsed and found valid,
65     but the file actually exists. */
66
67   const basis::astring &raw() const;
68     //!< returns the astring that we're holding onto for the path.
69   basis::astring &raw();
70     //!< accesses the astring that we're holding onto for the path.
71     /*!< important note: if you change the string with this non-const raw()
72     method, you MUST call canonicalize() on it again afterwards. */
73
74   filename &operator = (const filename &to_copy);
75     //!< provides assignment for this object, plus a simple string.
76   filename &operator = (const basis::astring &to_copy);
77     //!< provides assignment for this object, plus a simple string.
78     /*!< the latter version invokes canonicalize to clean the string up. */
79
80   void canonicalize();
81     //!< cleans up the filename as needed for the current operating system.
82     /*!< reforms the name by replacing any alternate directory separators with
83     the operating system's preferred character. */
84
85   bool exists() const;
86     //!< returns true if the file exists.
87
88   bool unlink() const;
89     //!< actually removes the file, if possible.
90     /*!< if the file was successfully deleted, then true is returned. */
91
92   filename parent() const;
93     //!< returns the parent filename for this one.
94
95   basis::astring pop();
96     //!< removes the deepest component of the pathname.
97     /*!< the component might be a file or directory name, but popping beyond
98     the top-level directory will not succeed.  the returned string contains
99     the component that was removed.  it will be a blank string if nothing
100     could be popped. */
101
102   void push(const basis::astring &to_push);
103     //!< pushes a new filename onto the current pathname.
104     /*!< this only makes sense as a real pathname if this is currently a
105     directory name and the component "to_push" is a child of that directory
106     (or one intends to create that component as a child).  this is the
107     opposite of pop. */
108
109   filename basename() const;
110     //!< returns the base of the filename; no directory.
111   filename dirname() const;
112     //!< returns the directory for the filename.
113     /*!< if no directory name can be found in the filename, then "." is
114     returned. */
115   basis::astring dirname(bool add_slash) const;
116     //!< returns the directory for the filename and optionally adds a slash.
117     /*!< if "add_slash" is true, then the default directory separator will be
118     present on the end of the string. */
119   bool had_directory() const { return _had_directory; }
120     //!< returns true if the name that we were given had a non-empty directory.
121     /*!< this allows one to distinguish between a file with the current
122     directory (.) attached and a file with no directory specified. */
123
124   char drive(bool interact_with_fs = false) const;
125     //!< returns the drive letter for the file, without the colon.
126     /*!< this only makes sense for a fully qualified MS-DOS style name.  if no
127     drive letter is found, then '\0' is returned.  if "interact_with_fs" is
128     true, then the file system will be checked for the actual drive if no
129     drive letter was found in the contents. */
130
131   basis::astring extension() const;
132     //!< returns the extension for the file, if one is present.
133
134   basis::astring rootname() const;
135     //!< returns the root part of the basename without an extension.
136
137   // status functions return true if the characteristic embodied in
138   // the name is also true.
139
140   bool is_directory() const;
141   bool is_writable() const;
142   bool is_readable() const;
143   bool is_executable() const;
144
145   enum write_modes {
146     ALLOW_NEITHER = 0x0,
147     ALLOW_READ = 0x1, ALLOW_WRITE = 0x2,
148     ALLOW_BOTH = ALLOW_READ | ALLOW_WRITE
149   };
150
151   enum ownership_modes {
152     NO_RIGHTS = 0x0,
153     USER_RIGHTS = 0x1, GROUP_RIGHTS = 0x2, OTHER_RIGHTS = 0x4,
154     ALL_RIGHTS = USER_RIGHTS | GROUP_RIGHTS | OTHER_RIGHTS
155   };
156
157   bool chmod(int write_mode, int owner_mode) const;
158     //!< changes the access rights on the file.
159
160   //! the default separator for directories per operating system.
161   /*! the PC uses the backward slash to separate file and directory names from
162   each other, while Unix uses the forward slash. */
163   enum directory_separator { pc_separator = '\\', unix_separator = '/' };
164
165   static bool separator(char is_it);
166     //!< returns true if the character "is_it" in question is a separator.
167
168   static basis::astring default_separator();
169     //!< returns the default separator character for this OS.
170
171   static bool legal_character(char to_check);
172     //!< returns true if "to_check" is a valid character in a filename.
173     /*!< this does not consider separator characters; it only looks at the
174     the name components.  also, it is appropriate for the union of the
175     operating systems we support. */
176
177   static void detooth_filename(basis::astring &to_clean, char replacement = '_');
178     //!< takes any known illegal file system characters out of "to_clean".
179     /*!< this prepares "to_clean" for use as a component in a larger filename
180     by ensuring that the file system will not reject the name (as long as a
181     suitable directory path is prepended to the name and permissions allow
182     the file to be created or accessed).  the "replacement" is used as the
183     character that is substituted instead of illegal characters. */
184
185   void separate(structures::string_array &pieces) const;
186     //!< breaks the filename into its component directories.
187     /*!< this returns an array containing the component names.  the last
188     component, unless the filename held is actually a directory, should be the
189     name of the file.  if the first character is a directory, then the first
190     component will be empty. */
191
192   void join(const structures::string_array &pieces);
193     //!< undoes a separate() operation to get the filename back.
194     /*!< "this" is set to a filename made from each of the "pieces".  if there
195     are any directory separators inside the pieces, then they will be removed
196     by canonicalize(). */
197
198   // these implement the packing functionality.
199   virtual void pack(basis::byte_array &packed_form) const;
200   virtual bool unpack(basis::byte_array &packed_form);
201   virtual int packed_size() const;
202
203   bool compare_prefix(const filename &to_compare, basis::astring &sequel);
204     //!< examines "this" filename to see if it's a prefix of "to_compare".
205     /*!< this returns true if all of "this" is the same as the first portion
206     of "to_compare".  that is, if "this" is a prefix of "to_compare", then
207     true is returned.  this will always fail if there are fewer components in
208     "to_compare".  it will always succeed if the two filenames are identical.
209     on success, the "sequel" is set to the portion of "to_compare" that's
210     not included in this filename. */
211
212   bool compare_prefix(const filename &to_compare);
213     //!< this simpler form doesn't bother with computing the sequel.
214
215   bool compare_suffix(const filename &to_compare, basis::astring &prequel);
216     //!< compares the back end of a filename to this.
217     /*!< this is similar to compare_prefix() but it checks to see if the
218     back end of "this" filename is the same as "to_compare".  if "this" is
219     longer than "to_compare", then failure occurs.  only if all of the bits
220     in "this" are seen in the back of "to_compare" is true returned. */
221
222   bool compare_suffix(const filename &to_compare);
223
224   static basis::astring null_device();
225     //!< returns the name for the black hole device that consumes all input, i.e. /dev/null.
226
227 private:
228   bool _had_directory;  //!< true if _some_ directory was specified on init.
229 ///  basis::astring *_contents;  //!< the full path is held here.
230
231   int find_last_separator(const basis::astring &look_at) const;
232     //!< locates the last separator character in the filename.
233
234   bool get_info(status_info *to_fill) const;
235     //!< returns information for the filename.
236
237   // helper functions do the real work for comparing.
238   bool base_compare_prefix(const filename &to_compare, structures::string_array &first,
239           structures::string_array &second);
240   bool base_compare_suffix(const filename &to_compare, structures::string_array &first,
241           structures::string_array &second);
242 };
243
244 } //namespace.
245
246 #endif
247