Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use .get_file() instead of basename from libc #51429

Merged
merged 1 commit into from
Oct 9, 2021

Conversation

omar-polo
Copy link
Contributor

@omar-polo omar-polo commented Aug 9, 2021

This fixes #48938

@omar-polo omar-polo requested a review from a team as a code owner August 9, 2021 09:40
@bruvzg bruvzg added this to the 4.0 milestone Aug 9, 2021
Copy link
Contributor

@theraot theraot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For what I've found basename and get_basename are not equivalent:

Given the name file_name, the fact that it will be used like this:

	String dest_path = trash_path + "/files/" + file_name;

And as far as I can tell, move_to_trash does not work for folders.

I think you should use get_file instead of get_basename. See https://docs.godotengine.org/en/latest/classes/class_string.html#class-string-method-get-file


The behavior of get_file differs from the description of basename in that it will return empty string if the input is empty string or consist only of /. I quote from http://man.openbsd.org/basename.3:

If path consists entirely of ‘/’ characters, a pointer to the string "/" is returned. If path is a null pointer or the empty string, a pointer to the string "." is returned.

The description of basename at https://www.man7.org/linux/man-pages/man3/basename.3.html (which that is not BSD) matches the description at http://man.openbsd.org/basename.3 and also provides some test cases:

              path       dirname   basename
              /usr/lib   /usr      lib
              /usr/      /         usr
              usr        .         usr
              /          /         /
              .          .         .
              ..         .         ..

Adding get_basename and get_file there for comparison, looks like this:

              path       dirname   basename   get_basename     get_file
              /usr/lib   /usr      lib        /usr/lib         lib
              /usr/      /         usr        /usr/            <empty string>
              usr        .         usr        usr              usr
              /          /         /          /                <empty string>
              .          .         .          <empty string>   .
              ..         .         ..         .                ..

Where <empty string> denotes the empty string.

You can see that if we assume we have a file path, then get_file is what we want.

@omar-polo
Copy link
Contributor Author

Thanks for checking! I've updated the PR.

I was confused because the similar naming, apologize.

@omar-polo
Copy link
Contributor Author

I forgot to update the commit message, here's another try

@omar-polo omar-polo changed the title use .get_basename() instead of basename from libc use .get_file() instead of basename from libc Oct 8, 2021
@theraot
Copy link
Contributor

theraot commented Oct 8, 2021

Sorry.

I had a look for usages of move_to_trash, and there is one that seems to use it on folders:

for (int i = 0; i < dirs_to_delete.size(); ++i) {
String path = OS::get_singleton()->get_resource_dir() + dirs_to_delete[i].replace_first("res://", "/");
print_verbose("Moving to trash: " + path);
Error err = OS::get_singleton()->move_to_trash(path);
if (err != OK) {
EditorNode::get_singleton()->add_io_error(TTR("Cannot remove:") + "\n" + dirs_to_delete[i] + "\n");
} else {
emit_signal(SNAME("folder_removed"), dirs_to_delete[i]);
}
}

If move_to_trash needs to support this, we need something better than get_file.

@theraot
Copy link
Contributor

theraot commented Oct 8, 2021

I wish there was a better API for this. However, let us take advantage of this pattern: get_base_dir().get_file()

I found example of it already in the source:

if (!path.get_base_dir().get_file().is_empty()) {

That would give us the name of the folder (but not of the file).

Copy link
Contributor

@theraot theraot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what I suggest:

	String file_name = p_path.get_file();
	if (file_name.length() == 0) {
		file_name = p_path.get_base_dir().get_file();
	}

That way, if p_path points to a file, p_path.get_file() gives us the name of the file. Otherwise, we get empty string and enter the conditional, where p_path.get_base_dir().get_file() gives us the name of the folder.

On OpenBSD the compiler complains that calling basename(3) would lose
const qualifier.  basename(3) is defined as

	char *basename(char *);

and can, accorgindly to the POSIX.1, modify the passed string.

This uses the .get_file() method.  The check is necessary because
file_name could be a directory, in which case .get_file() would return
an empty string.  The .get_base_dir().get_file() idiom is already used.

The usage of get_file() and the check were suggested by theraot, thanks!
@omar-polo
Copy link
Contributor Author

Thanks for the suggestion! I'm not really comfortable writing C++ yet.

Yep, I wish there were better API too. (but this applies also to libc, basename(3) alter the passed string :/)

I've also improved the commit message, hope it's not too long ^^

@theraot
Copy link
Contributor

theraot commented Oct 9, 2021

I, of course, approve this. Because of course.

@akien-mga akien-mga merged commit 1f192c4 into godotengine:master Oct 9, 2021
@akien-mga
Copy link
Member

Thanks!

@akien-mga akien-mga added the cherrypick:3.x Considered for cherry-picking into a future 3.x release label Oct 9, 2021
@akien-mga
Copy link
Member

Cherry-picked for 3.4.

@akien-mga akien-mga removed the cherrypick:3.x Considered for cherry-picking into a future 3.x release label Oct 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

can't find basename() on OpenBSD
4 participants