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