bool filename::unlink() const { return ::unlink(observe()) == 0; }
+void filename::reset(const astring &name) {
+ *this = name;
+ _had_directory = true; // until we know better.
+ canonicalize();
+}
+
astring filename::null_device()
{
#ifdef __WIN32__
+ astring(DEFAULT_SEPARATOR, 1));
// must be at least as long as the string we're looking for, plus a drive letter afterwards.
if ( (length() > CYGDRIVE_PATH.length() + 1) && begins(CYGDRIVE_PATH) ) {
- zap(0, CYGDRIVE_PATH.length() + 1); // whack the cygdrive portion plus two slashes.
+ zap(0, CYGDRIVE_PATH.length() - 1); // whack the cygdrive portion plus two slashes.
insert(1, ":"); // add a colon after the imputed drive letter.
+LOG(astring("turned cygdrive string into: ") + *this);
}
// now we convert msys...
- if ( (length() >= 2) && (get(0) == DEFAULT_SEPARATOR) && textual::parser_bits::is_alpha(get(1)) ) {
+ if ( (length() >= 2) && (get(0) == DEFAULT_SEPARATOR)
+ && textual::parser_bits::is_alpha(get(1)) ) {
// we seem reasonably sure now that this is a windows path hiding in msys format, but
// the next character needs to be a slash (if there is a next character) for it to be
// the windows drive form. otherwise it could be /tmp, which would obviously not be
// intended as a windows path.
- if ( (length() < 3) || (get(2) == DEFAULT_SEPARATOR) ) {
+ if ( (length() == 2) || (get(2) == DEFAULT_SEPARATOR) ) {
// cool, this should be interpretable as an msys path, except for those wacky types
- // that use top-level single character directory names. we cannot help that, because
- // we *know* msys is a choice used in other code a lot.
-//hmmm: future revision: see if the file or directory '/x' actually exists on current drive? yuck.
+ // of folks that might use a top-level single character directory name. we cannot
+ // help them, because we have made a design decision to support msys-style paths.
+ // note that this would only affect someone if they were referring to their directory on
+ // the current windows partition (c:, d:, etc.) without providing the drive letter,
+ // if they had that single character directory name (e.g., c:\x, d:\q, etc.) and even
+ // then only on the near defunct windows platform.
zap(0, 0); // take off initial slash.
insert(1, ":"); // add the obligatory colon.
+LOG(astring("turned msys string into: ") + *this);
}
}
#endif
-LOG(astring("ha ha turned string into: ") + *this);
-
// we don't crop the last separator if the name's too small. for msdos
// names, that would be chopping a slash off the c:\ style name.
if (length() > 3) {
return !!(fill.st_mode & S_IEXEC);
}
+bool filename::is_normal() const
+{
+ status_info fill;
+ if (!get_info(&fill))
+ return false;
+#if defined(__WIN32__) || defined(__VMS__)
+//hmmm: is there a corresponding set of functions for windows, where applicable?
+ bool weird = false;
+#else
+ bool weird = S_ISCHR(fill.st_mode)
+ || S_ISBLK(fill.st_mode)
+ || S_ISFIFO(fill.st_mode)
+ || S_ISSOCK(fill.st_mode);
+#endif
+ return !weird;
+}
+
int filename::find_last_separator(const astring &look_at) const
{
int last_sep = -1;
{
if (is_directory())
return true;
+ // if the file name is empty, that cannot exist.
if (!length())
return false;
return is_readable();
-/// byte_filer opened(observe(), "rb");
-/// return opened.good();
}
bool filename::legal_character(char to_check)
return true;
}
-void filename::separate(string_array &pieces) const
+void filename::separate(bool &rooted, string_array &pieces) const
{
pieces.reset();
const astring &raw_form = raw();
astring accumulator; // holds the names we find.
+ rooted = raw_form.length() && separator(raw_form[0]);
for (int i = 0; i < raw_form.length(); i++) {
if (separator(raw_form[i])) {
// this is a separator character, so eat it and add the accumulated
// string to the list.
- if (!i || accumulator.length()) pieces += accumulator;
+ if (i && accumulator.length()) pieces += accumulator;
// now reset our accumulated text.
accumulator = astring::empty_string();
} else {
if (accumulator.length()) pieces += accumulator;
}
-void filename::join(const string_array &pieces)
+void filename::join(bool rooted, const string_array &pieces)
{
astring constructed_name; // we'll make a filename here.
+ if (rooted) constructed_name += DEFAULT_SEPARATOR;
for (int i = 0; i < pieces.length(); i++) {
constructed_name += pieces[i];
if (!i || (i != pieces.length() - 1))
bool filename::base_compare_prefix(const filename &to_compare,
string_array &first, string_array &second)
{
- separate(first);
- to_compare.separate(second);
+ bool first_rooted;
+ separate(first_rooted, first);
+ bool second_rooted;
+ to_compare.separate(second_rooted, second);
+ if (first_rooted != second_rooted) {
+ return false;
+ }
// that case should never be allowed, since there are some bits missing
// in the name to be compared.
if (first.length() > second.length())
bool filename::base_compare_suffix(const filename &to_compare,
string_array &first, string_array &second)
{
- separate(first);
- to_compare.separate(second);
+ bool first_rooted;
+ separate(first_rooted, first);
+ bool second_rooted;
+ to_compare.separate(second_rooted, second);
// that case should never be allowed, since there are some bits missing
// in the name to be compared.
if (first.length() > second.length())