feisty meow concerns codebase  2.140
filename.cpp
Go to the documentation of this file.
1 /*****************************************************************************\
2 * *
3 * Name : filename *
4 * Author : Chris Koeritz *
5 * *
6 *******************************************************************************
7 * Copyright (c) 1993-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
14 
15 // implementation note: the filename is kept canonicalized. any constructor
16 // or assignment operator should ensure this (except the blank constructor).
17 
18 #include "filename.h"
19 
20 #include <basis/byte_array.h>
21 #include <basis/functions.h>
22 #include <textual/parser_bits.h>
23 #include <system_helper.h>
24 
25 #include <stdio.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #if defined(__UNIX__) || defined(__GNU_WINDOWS__)
29  #include <unistd.h>
30 #else
31  #include <io.h>
32 #endif
33 
34 #undef LOG
35 #define LOG(to_print) printf("%s::%s: %s\n", static_class_name(), func, astring(to_print).s())
36 
37 using namespace basis;
38 using namespace structures;
39 
40 class status_info : public stat
41 {
42 };
43 
44 namespace filesystem {
45 
46 //#if defined(__WIN32__) || defined(__VMS__)
47 // const char DEFAULT_SEPARATOR = '\\';
48 //#elif defined(__UNIX__)
49  const char DEFAULT_SEPARATOR = '/';
50 //#else
51 // #error "We have no idea what the default path separator is."
52 //#endif
53 
54 const char *NO_PARENT_DEFAULT = ".";
55  // used when no directory name can be popped off.
56 
57 filename::filename()
58 : astring(),
59  _had_directory(false)
60 {}
61 
63 : astring(name),
64  _had_directory(true)
65 { canonicalize(); }
66 
67 filename::filename(const astring &directory, const astring &name_of_file)
69  _had_directory(true)
70 {
71  // if the directory is empty, use the current directory.
72  if (!directory) {
73  *this = astring(NO_PARENT_DEFAULT);
74  _had_directory = false;
75  }
76  // check for a slash on the end of the directory. add one if there is none
77  // currently.
78  bool add_slash = false;
79  if ( (directory[directory.end()] != '\\')
80  && (directory[directory.end()] != '/') ) add_slash = true;
81  if (add_slash) *this += DEFAULT_SEPARATOR;
82  *this += name_of_file;
83  canonicalize();
84 }
85 
87 : astring(to_copy),
88  _had_directory(to_copy._had_directory)
89 { canonicalize(); }
90 
92 
94 
95 astring &filename::raw() { return *this; }
96 
97 const astring &filename::raw() const { return *this; }
98 
99 bool filename::good() const { return exists(); }
100 
101 bool filename::unlink() const { return ::unlink(observe()) == 0; }
102 
103 void filename::reset(const astring &name) {
104  *this = name;
105  _had_directory = true; // until we know better.
106  canonicalize();
107 }
108 
110 {
111 #ifdef __WIN32__
112  return "null:";
113 #else
114  return "/dev/null";
115 #endif
116 }
117 
118 bool filename::separator(char is_it)
119 { return (is_it == pc_separator) || (is_it == unix_separator); }
120 
122 {
123  if (this == &to_copy) return *this;
124  (astring &)(*this) = to_copy;
125  _had_directory = to_copy._had_directory;
126  return *this;
127 }
128 
130 {
131  _had_directory = true;
132  if (this == &to_copy) return *this;
133  (astring &)(*this) = to_copy;
134  canonicalize();
135  return *this;
136 }
137 
139 {
140  astring to_return = basename();
141  filename parent_dir = parent();
142  if (parent_dir.raw().equal_to(NO_PARENT_DEFAULT)) {
143  // we haven't gone anywhere.
144  return ""; // signal that nothing was removed.
145  }
146  *this = parent_dir;
147  return to_return;
148 }
149 
150 filename filename::parent() const { return dirname(); }
151 
152 void filename::push(const astring &to_push)
153 {
154  *this = filename(*this, to_push);
155 }
156 
158 {
159  FUNCDEF("canonicalize");
160  // turn all the non-default separators into the default.
161  bool found_sep = false;
162  for (int j = 0; j < length(); j++) {
163  if (separator(get(j))) {
164  found_sep = true;
166  }
167  }
168 
169  // if there wasn't a single directory separator, then they must not have
170  // specified any directory name for this filename (although it could itself
171  // be a directory).
172  if (!found_sep) _had_directory = false;
173 
174  // remove all occurrences of double separators except for the first
175  // double set, which could be a UNC filename. that's why the index below
176  // starts at one rather than zero.
177  bool saw_sep = false;
178  for (int i = 1; i < length(); i++) {
179  if (separator(get(i))) {
180  if (saw_sep) {
181  zap(i, i);
182  // two in a row is no good, except for the first two.
183  i--; // skip back one and try again.
184  continue;
185  }
186  saw_sep = true;
187  } else saw_sep = false;
188  }
189 
190 #ifdef __WIN32__
191  // on windows, we want to translate away from any cygwin or msys format into a more palatable
192  // version that the rest of windows understands.
193  // first, cygwin...
194 //hmmm: make these into statics!
195  const astring CYGDRIVE_SENTINEL = "cygdrive";
196  const astring CYGDRIVE_PATH = astring(astring(DEFAULT_SEPARATOR, 1)
197  + CYGDRIVE_SENTINEL + astring(DEFAULT_SEPARATOR, 1));
198 
199  // must be at least as long as the string we're looking for, plus a drive letter afterwards.
200  if ( (length() >= CYGDRIVE_PATH.length() + 1)
201  && separator(get(0))
202  && separator(get(CYGDRIVE_PATH.length() - 1))
203  && compare(CYGDRIVE_SENTINEL, 1,
204  0, CYGDRIVE_SENTINEL.length(), true) ) {
205  zap(0, CYGDRIVE_PATH.length() - 1); // whack the cygdrive portion plus two slashes.
206  insert(1, ":"); // add a colon after the imputed drive letter.
207 //LOG(astring("turned cygdrive path string into: ") + *this);
208  } else {
209 //LOG(astring("path didn't match so left as: ") + *this);
210  }
211 
212  // now we convert msys...
213  if ( (length() >= 2) && (get(0) == DEFAULT_SEPARATOR)
215  // we seem reasonably sure now that this is a windows path hiding in msys format, but
216  // the next character needs to be a slash (if there is a next character) for it to be
217  // the windows drive form. otherwise it could be /tmp, which would obviously not be
218  // intended as a windows path.
219  if ( (length() == 2) || (get(2) == DEFAULT_SEPARATOR) ) {
220  // cool, this should be interpretable as an msys path, except for those wacky types
221  // of folks that might use a top-level single character directory name. we cannot
222  // help them, because we have made a design decision to support msys-style paths.
223  // note that this would only affect someone if they were referring to their directory on
224  // the current windows partition (c:, d:, etc.) without providing the drive letter,
225  // if they had that single character directory name (e.g., c:\x, d:\q, etc.) and even
226  // then only on the near defunct windows platform.
227  zap(0, 0); // take off initial slash.
228  insert(1, ":"); // add the obligatory colon.
229 //LOG(astring("turned msys string into: ") + *this);
230  }
231  }
232 
233  // if we still have a unix style path here on windows, then there will be
234  // trouble when we pass that to the OS. we are not using any cygwin or
235  // other virtualization libraries directly, so we can't rely on those to
236  // fix the path. but if we built under something like cygwin, we should
237  // have stored the real dos-style location of the virtual unix root. we
238  // will use that to replace the root '/' and this should fix most of that
239  // style of path.
240  bool inject_root = false; // assume we don't need to do anything.
241 
242 //LOG(astring("before root injection: ") + raw());
243 
244  // condition here just checks if the path is only the root.
245  if ( (length() == 1) && separator(get(0)) ) { inject_root = true; }
246 
247 //if (inject_root) LOG("decided to inject root since path is '/'.");
248 
249  // condition is looking for first character being a slash, and second char as alphanumeric or dash or underscore.
250  // we will currently fail detecting freaky paths that don't start off with alphanumeric or one of that small set of special chars.
251  if ( (length() >= 2)
252  && separator(get(0))
253  && ( textual::parser_bits::is_alphanumeric(get(1)) || ('-' == get(1)) || ('_' == get(1)) ) ) {
254  inject_root = true;
255 //if (inject_root) LOG(astring("decided to inject root since path is compatible: ") + *this);
256  }
257 
258 //LOG(astring("after second phase root injection: ") + raw());
259 
260  if (inject_root) {
261  // inject the actual path to the unix root in front, if we know it.
262  // if we don't know it, then a default path that's unlikely to work is idiotically plugged in.
263  insert(0, FEISTY_MEOW_VIRTUAL_UNIX_ROOT);
264 //LOG(astring("turned cygdrive path string into: ") + raw());
265  }
266 #endif
267 
268  // we don't crop the last separator if the name's too small. for msdos
269  // names, that would be chopping a slash off the c:\ style name.
270  if (length() > 3) {
271  // zap any separators that are hiding on the end.
272  const int last = end();
273  if (separator(get(last))) zap(last, last);
274  } else if ( (length() == 2) && (get(1) == ':') ) {
275  // special case for dos drive names. we turn it back into a valid
276  // directory rather than leaving it as just "X:". that form of the name
277  // means something else under dos/windows.
278  *this += astring(DEFAULT_SEPARATOR, 1);
279  }
280 }
281 
282 char filename::drive(bool interact_with_fs) const
283 {
284  // first guess: if second letter's a colon, first letter's the drive.
285  if (length() < 2)
286  return '\0';
287  if (get(1) == ':')
288  return get(0);
289  if (!interact_with_fs)
290  return '\0';
291 
292  // otherwise, retrieve the file system's record for the file.
293  status_info fill;
294  if (!get_info(&fill))
295  return '\0';
296  return char('A' + fill.st_dev);
297 }
298 
300 {
301  astring base(basename().raw());
302  int posn = base.find('.', base.end(), true);
303  if (negative(posn))
304  return "";
305  return base.substring(posn + 1, base.length() - 1);
306 }
307 
309 {
310  astring base(basename().raw());
311  int posn = base.find('.', base.end(), true);
312  if (negative(posn))
313  return base;
314  return base.substring(0, posn - 1);
315 }
316 
317 bool filename::get_info(status_info *to_fill) const
318 {
319  int ret = stat(observe(), to_fill);
320  if (ret)
321  return false;
322  return true;
323 }
324 
326 {
327  status_info fill;
328  if (!get_info(&fill))
329  return false;
330  return !!(fill.st_mode & S_IFDIR);
331 }
332 
334 {
335  status_info fill;
336  if (!get_info(&fill))
337  return false;
338  return !!(fill.st_mode & S_IWRITE);
339 }
340 
342 {
343  status_info fill;
344  if (!get_info(&fill))
345  return false;
346  return !!(fill.st_mode & S_IREAD);
347 }
348 
350 {
351  status_info fill;
352  if (!get_info(&fill))
353  return false;
354  return !!(fill.st_mode & S_IEXEC);
355 }
356 
358 {
359  status_info fill;
360  if (!get_info(&fill))
361  return false;
362 #if defined(__WIN32__) || defined(__VMS__)
363 //hmmm: is there a corresponding set of functions for windows, where applicable?
364  bool weird = false;
365 #else
366  bool weird = S_ISCHR(fill.st_mode)
367  || S_ISBLK(fill.st_mode)
368  || S_ISFIFO(fill.st_mode)
369  || S_ISSOCK(fill.st_mode);
370 #endif
371  return !weird;
372 }
373 
374 int filename::find_last_separator(const astring &look_at) const
375 {
376  int last_sep = -1;
377  int sep = 0;
378  while (sep >= 0) {
379  sep = look_at.find(DEFAULT_SEPARATOR, last_sep + 1);
380  if (sep >= 0) last_sep = sep;
381  }
382  return last_sep;
383 }
384 
386 {
387  astring basename = *this;
388  int last_sep = find_last_separator(basename);
389  if (last_sep >= 0) basename.zap(0, last_sep);
390  return basename;
391 }
392 
394 {
395  astring dirname = *this;
396  int last_sep = find_last_separator(dirname);
397  // we don't accept ripping off the first slash.
398  if (last_sep >= 1) {
399  // we can rip the slash and suffix off to get the directory name. however,
400  // this might be in the form X: on windows. if they want the slash to
401  // remain, they can use the dirname that appends it.
402  dirname.zap(last_sep, dirname.end());
403  } else {
404  if (get(0) == DEFAULT_SEPARATOR) {
405  // handle when we're up at the top of the filesystem. on unix, once
406  // you hit the root, you can keep going up but you still remain at
407  // the root. similarly on windoze, if there's no drive name in there.
409  } else {
410  // there's no slash at all in the filename any more. we assume that
411  // the directory is the current one, if no other information is
412  // available. this default is already used by some code.
414  }
415  }
416  return dirname;
417 }
418 
419 astring filename::dirname(bool add_slash) const
420 {
421  astring tempname = dirname().raw();
422  if (add_slash) tempname += DEFAULT_SEPARATOR;
423  return tempname;
424 }
425 
426 bool filename::exists() const
427 {
428  if (is_directory())
429  return true;
430  // if the file name is empty, that cannot exist.
431  if (!length())
432  return false;
433  return is_readable();
434 }
435 
436 bool filename::legal_character(char to_check)
437 {
438  switch (to_check) {
439  case ':': case ';':
440  case '\\': case '/':
441  case '*': case '?': case '$': case '&': case '|':
442  case '\'': case '"': case '`':
443  case '(': case ')':
444  case '[': case ']':
445  case '<': case '>':
446  case '{': case '}':
447  return false;
448  default: return true;
449  }
450 }
451 
452 void filename::detooth_filename(astring &to_clean, char replacement)
453 {
454  for (int i = 0; i < to_clean.length(); i++) {
455  if (!legal_character(to_clean[i]))
456  to_clean[i] = replacement;
457  }
458 }
459 
461 {
463 }
464 
465 void filename::pack(byte_array &packed_form) const
466 {
467  attach(packed_form, int(_had_directory));
468  astring::pack(packed_form);
469 }
470 
471 bool filename::unpack(byte_array &packed_form)
472 {
473  int temp;
474  if (!detach(packed_form, temp))
475  return false;
476  _had_directory = temp;
477  if (!astring::unpack(packed_form))
478  return false;
479  return true;
480 }
481 
482 void filename::separate(bool &rooted, string_array &pieces) const
483 {
484  pieces.reset();
485  const astring &raw_form = raw();
486  astring accumulator; // holds the names we find.
487  rooted = raw_form.length() && separator(raw_form[0]);
488  for (int i = 0; i < raw_form.length(); i++) {
489  if (separator(raw_form[i])) {
490  // this is a separator character, so eat it and add the accumulated
491  // string to the list.
492  if (i && accumulator.length()) pieces += accumulator;
493  // now reset our accumulated text.
494  accumulator = astring::empty_string();
495  } else {
496  // not a separator, so just accumulate it.
497  accumulator += raw_form[i];
498  }
499  }
500  if (accumulator.length()) pieces += accumulator;
501 }
502 
503 void filename::join(bool rooted, const string_array &pieces)
504 {
505  astring constructed_name; // we'll make a filename here.
506  if (rooted) constructed_name += DEFAULT_SEPARATOR;
507  for (int i = 0; i < pieces.length(); i++) {
508  constructed_name += pieces[i];
509  if (!i || (i != pieces.length() - 1))
510  constructed_name += DEFAULT_SEPARATOR;
511  }
512  *this = constructed_name;
513 }
514 
515 bool filename::base_compare_prefix(const filename &to_compare,
516  string_array &first, string_array &second)
517 {
518  bool first_rooted;
519  separate(first_rooted, first);
520  bool second_rooted;
521  to_compare.separate(second_rooted, second);
522  if (first_rooted != second_rooted) {
523  return false;
524  }
525  // that case should never be allowed, since there are some bits missing
526  // in the name to be compared.
527  if (first.length() > second.length())
528  return false;
529 
530  // compare each of the pieces.
531  for (int i = 0; i < first.length(); i++) {
532 #if defined(__WIN32__) || defined(__VMS__)
533  // case-insensitive compare.
534  if (!first[i].iequals(second[i]))
535  return false;
536 #else
537  // case-sensitive compare.
538  if (first[i] != second[i])
539  return false;
540 #endif
541  }
542  return true;
543 }
544 
545 bool filename::compare_prefix(const filename &to_compare, astring &sequel)
546 {
547  sequel = astring::empty_string(); // clean our output parameter.
548  string_array first;
549  string_array second;
550  if (!base_compare_prefix(to_compare, first, second))
551  return false;
552 
553  // create the sequel string.
554  int extra_strings = second.length() - first.length();
555  for (int i = second.length() - extra_strings; i < second.length(); i++) {
556  sequel += second[i];
557  if (i != second.length() - 1) sequel += DEFAULT_SEPARATOR;
558  }
559 
560  return true;
561 }
562 
563 bool filename::compare_prefix(const filename &to_compare)
564 {
565  string_array first;
566  string_array second;
567  return base_compare_prefix(to_compare, first, second);
568 }
569 
570 bool filename::base_compare_suffix(const filename &to_compare,
571  string_array &first, string_array &second)
572 {
573  bool first_rooted;
574  separate(first_rooted, first);
575  bool second_rooted;
576  to_compare.separate(second_rooted, second);
577  // that case should never be allowed, since there are some bits missing
578  // in the name to be compared.
579  if (first.length() > second.length())
580  return false;
581 
582  // compare each of the pieces.
583  for (int i = first.length() - 1; i >= 0; i--) {
584 //clean up this computation; the difference in lengths is constant--use that.
585  int distance_from_end = first.length() - 1 - i;
586  int j = second.length() - 1 - distance_from_end;
587 #if defined(__WIN32__) || defined(__VMS__)
588  // case-insensitive compare.
589  if (!first[i].iequals(second[j]))
590  return false;
591 #else
592  // case-sensitive compare.
593  if (first[i] != second[j])
594  return false;
595 #endif
596  }
597  return true;
598 }
599 
600 bool filename::compare_suffix(const filename &to_compare, astring &prequel)
601 {
602  prequel = astring::empty_string(); // clean our output parameter.
603  string_array first;
604  string_array second;
605  if (!base_compare_suffix(to_compare, first, second))
606  return false;
607 
608  // create the prequel string.
609  int extra_strings = second.length() - first.length();
610  for (int i = 0; i < extra_strings; i++) {
611  prequel += second[i];
612  if (i != second.length() - 1) prequel += DEFAULT_SEPARATOR;
613  }
614  return true;
615 }
616 
617 bool filename::compare_suffix(const filename &to_compare)
618 {
619  string_array first;
620  string_array second;
621  return base_compare_suffix(to_compare, first, second);
622 }
623 
624 bool filename::chmod(int write_mode, int owner_mode) const
625 {
626  int chmod_value = 0;
627 #ifdef __UNIX__
628  if (write_mode & ALLOW_READ) {
629  if (owner_mode & USER_RIGHTS) chmod_value |= S_IRUSR;
630  if (owner_mode & GROUP_RIGHTS) chmod_value |= S_IRGRP;
631  if (owner_mode & OTHER_RIGHTS) chmod_value |= S_IROTH;
632  }
633  if (write_mode & ALLOW_WRITE) {
634  if (owner_mode & USER_RIGHTS) chmod_value |= S_IWUSR;
635  if (owner_mode & GROUP_RIGHTS) chmod_value |= S_IWGRP;
636  if (owner_mode & OTHER_RIGHTS) chmod_value |= S_IWOTH;
637  }
639 #elif defined(__WIN32__)
640  if (write_mode & ALLOW_READ) {
641  chmod_value |= _S_IREAD;
642  }
643  if (write_mode & ALLOW_WRITE) {
644  chmod_value |= _S_IWRITE;
645  }
646 #else
647  #error unsupported OS type currently.
648 #endif
649  int chmod_result = ::chmod(raw().s(), chmod_value);
650  if (chmod_result) {
651 // LOG(astring("there was a problem changing permissions on ") + raw());
652  return false;
653  }
654  return true;
655 }
656 
657 } //namespace.
658 
#define stat
Definition: Xos2defs.h:41
#define unlink
Definition: Xos2defs.h:45
#define S_IFDIR
Definition: Xw32defs.h:60
#define S_IWRITE
Definition: Xw32defs.h:64
#define S_IEXEC
Definition: Xw32defs.h:65
#define S_IREAD
Definition: Xw32defs.h:63
void reset(int number=0, const contents *initial_contents=NULL_POINTER)
Resizes this array and sets the contents from an array of contents.
Definition: array.h:349
int length() const
Returns the current reported length of the allocated C array.
Definition: array.h:115
Provides a dynamically resizable ASCII character string.
Definition: astring.h:35
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition: astring.h:113
virtual char get(int index) const
a constant peek at the string's internals at the specified index.
Definition: astring.cpp:138
virtual void zap(int start, int end)
Deletes the characters between "start" and "end" inclusively.
Definition: astring.cpp:521
astring()
constructs an empty string.
Definition: astring.cpp:59
bool substring(astring &target, int start, int end) const
a version that stores the substring in an existing "target" string.
Definition: astring.cpp:865
bool iequals(const astring &that) const
returns true if this is case-insensitively equal to "that".
Definition: astring.cpp:565
void insert(int position, const astring &to_insert)
Copies "to_insert" into "this" at the "position".
Definition: astring.cpp:892
void reset()
clears out the contents string.
Definition: astring.h:202
bool equal_to(const char *that) const
returns true if "that" is equal to this.
Definition: astring.cpp:159
int end() const
returns the index of the last (non-null) character in the string.
Definition: astring.h:86
virtual void put(int position, char to_put)
stores the character "to_put" at index "position" in the string.
Definition: astring.h:138
int length() const
Returns the current length of the string.
Definition: astring.cpp:132
bool compare(const astring &to_compare, int start_first, int start_second, int count, bool case_sensitive) const
Compares "this" string with "to_compare".
Definition: astring.cpp:810
int find(char to_find, int position=0, bool reverse=false) const
Locates "to_find" in "this".
Definition: astring.cpp:574
virtual const char * observe() const
observes the underlying pointer to the zero-terminated string.
Definition: astring.cpp:140
A very common template for a dynamic array of bytes.
Definition: byte_array.h:36
Implements a scanner that finds all filenames in the directory specified.
Definition: directory.h:27
Provides operations commonly needed on file names.
Definition: filename.h:64
bool exists() const
returns true if the file exists.
Definition: filename.cpp:426
static bool separator(char is_it)
returns true if the character "is_it" in question is a separator.
Definition: filename.cpp:118
bool is_readable() const
Definition: filename.cpp:341
void canonicalize()
cleans up the filename as needed for the current operating system.
Definition: filename.cpp:157
virtual ~filename()
Definition: filename.cpp:91
void join(bool rooted, const structures::string_array &pieces)
undoes a separate() operation to get the filename back.
Definition: filename.cpp:503
bool good() const
returns true if the filename seems to be valid.
Definition: filename.cpp:99
virtual bool unpack(basis::byte_array &packed_form)
Restores the packable from the "packed_form".
Definition: filename.cpp:471
bool is_normal() const
Definition: filename.cpp:357
void separate(bool &rooted, structures::string_array &pieces) const
breaks the filename into its component parts.
Definition: filename.cpp:482
bool compare_prefix(const filename &to_compare, basis::astring &sequel)
examines "this" filename to see if it's a prefix of "to_compare".
Definition: filename.cpp:545
static basis::astring default_separator()
returns the default separator character for this OS.
Definition: filename.cpp:93
basis::astring extension() const
returns the extension for the file, if one is present.
Definition: filename.cpp:299
filename parent() const
returns the parent filename for this one.
Definition: filename.cpp:150
virtual void pack(basis::byte_array &packed_form) const
Creates a packed form of the packable object in "packed_form".
Definition: filename.cpp:465
char drive(bool interact_with_fs=false) const
returns the drive letter for the file, without the colon.
Definition: filename.cpp:282
basis::astring rootname() const
returns the root part of the basename without an extension.
Definition: filename.cpp:308
bool compare_suffix(const filename &to_compare, basis::astring &prequel)
compares the back end of a filename to this.
Definition: filename.cpp:600
static basis::astring null_device()
returns the name for the black hole device that consumes all input, i.e. /dev/null.
Definition: filename.cpp:109
bool chmod(int write_mode, int owner_mode) const
changes the access rights on the file.
Definition: filename.cpp:624
bool is_directory() const
Definition: filename.cpp:325
void push(const basis::astring &to_push)
pushes a new filename onto the current pathname.
Definition: filename.cpp:152
bool is_writable() const
Definition: filename.cpp:333
const basis::astring & raw() const
returns the astring that we're holding onto for the path.
Definition: filename.cpp:97
filename dirname() const
returns the directory for the filename.
Definition: filename.cpp:393
bool is_executable() const
Definition: filename.cpp:349
bool unlink() const
actually removes the file, if possible.
Definition: filename.cpp:101
static void detooth_filename(basis::astring &to_clean, char replacement='_')
takes any known illegal file system characters out of "to_clean".
Definition: filename.cpp:452
filename basename() const
returns the base of the filename; no directory.
Definition: filename.cpp:385
basis::astring pop()
removes the deepest component of the pathname.
Definition: filename.cpp:138
filename & operator=(const filename &to_copy)
provides assignment for this object, plus a simple string.
Definition: filename.cpp:121
static bool legal_character(char to_check)
returns true if "to_check" is a valid character in a filename.
Definition: filename.cpp:436
virtual int packed_size() const
Estimates the space needed for the packed structure.
Definition: filename.cpp:460
filename()
blank constructor.
Definition: filename.cpp:57
An array of strings with some additional helpful methods.
Definition: string_array.h:32
static bool is_alpha(char look_at)
returns true if "look_at" is one of the alphabetical characters.
static bool is_alphanumeric(char look_at)
returns true if "look_at" is one of the alphanumeric characters.
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition: enhance_cpp.h:57
The guards collection helps in testing preconditions and reporting errors.
Definition: array.h:30
void attach(byte_array &packed_form, const char *to_attach)
Packs a character string "to_attach" into "packed_form".
Definition: astring.cpp:1015
bool detach(byte_array &packed_form, astring &to_detach)
Unpacks a character string "to_attach" from "packed_form".
Definition: astring.cpp:1023
bool negative(const type &a)
negative returns true if "a" is less than zero.
Definition: functions.h:43
A platform independent way to obtain the timestamp of a file.
Definition: byte_filer.cpp:37
const char DEFAULT_SEPARATOR
Definition: filename.cpp:49
const char * NO_PARENT_DEFAULT
Definition: filename.cpp:54
A dynamic container class that holds any kind of object via pointers.
Definition: amorph.h:55
bool unpack(basis::byte_array &packed_form, set< contents > &to_unpack)
provides a way to unpack any set that stores packable objects.
Definition: set.h:139
void pack(basis::byte_array &packed_form, const set< contents > &to_pack)
provides a way to pack any set that stores packable objects.
Definition: set.h:131
const int PACKED_SIZE_INT32
int packed_size(const byte_array &packed_form)
Reports the size required to pack a byte array into a byte array.