-
Notifications
You must be signed in to change notification settings - Fork 41
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
Dangerous fault in the behaviour of cwk_path_join #18
Comments
Hi @naphthasl ! Thanks for submitting this issue! I believe the behaviour you are looking for is provided by cwk_path_get_absolute, which I believe generates an absolute path the way you describe. cwk_path_join is currently designed to actually join the two path segments. Does that help you, or do you need additional functionality? |
Is In the vast majority of higher level languages, there is a function for joining two paths by walking through them, as I demonstrated with Python in my initial post. The problem is that The important takeaway here is that joining together
I appreciate that my explanation is kind of difficult to understand, but seriously, take a look at
You will notice that os.path.join does not automatically remove the So, to summarize - with pretty much every other path library, if you want to walk from one directory to another, you join their paths and then normalize them. You can see how the normalization step works in Python, too:
I'm not really sure where you went wrong here - I think you may have misunderstood the "join" operation as some kind of "normalized concatenation" which is not what a join is supposed to do, because this "normalized concatenation" is not useful for the vast majority of programs, but a "normalized join" or "normalized walk" is extremely useful. Essentially, you really, really need a function that replicates the output of |
Okay, Note: My worry is that people might be using |
Hi @naphthasl, thanks for your detailed response and explanation. I will definitely give this a thought on how I can improve it and at least be more clear in the documentation. I understand the behaviour might be different to other libraries and this could cause confusion. Please be careful, cwk_path_get_relative generates a relative path and does not do the same as Python's path join! |
You're right, neither Also, Since we've been using Python equivalents a lot lately:
|
cwalk does not actually resolve files on the disk, that's because it is much more portable this way. But cwk_path_get_absolute can actually do more than python's abspath because it accepts a base path. You can simply supply your current working directory as a base path to achieve a similar result though: #include <stdio.h>
#include <stdlib.h>
#include <cwalk.h>
#ifdef _WIN32
#include <direct.h>
#define getcwd _getcwd
#elif
#include <unistd.h>
#endif
int main(int argc, char *argv[]) {
char buffer[FILENAME_MAX];
char cwd[FILENAME_MAX];
if(!getcwd(cwd, sizeof(cwd))) {
return EXIT_FAILURE;
}
cwk_path_get_absolute(cwd, ".", buffer, sizeof(buffer));
printf("%s\n", buffer); // should output /home/naphtha/Code/HAZE/testgame/shaders depending on your working directory
return EXIT_SUCCESS;
} |
Ah, I must've misunderstood how your Here's an idea, though. Instead of renaming or rewriting anything, maybe there could be an extra function called #ifndef MAX_CWD
#define MAX_CWD 4096
#endif
size_t cwk_fs_path_join(const char *base, const char *path, char *buffer, size_t buffer_size)
{
char cwd[MAX_CWD];
if(!getcwd(cwd, MAX_CWD)) return 0;
cwk_path_get_absolute(cwd, base, buffer, buffer_size);
cwk_path_get_absolute(buffer, path, buffer, buffer_size);
return cwk_path_get_relative(cwd, buffer, buffer, buffer_size);
} That way, you can retain the portability of the existing functions while providing easy to use alternatives for people who are looking to replicate functionality similar to other languages. |
I had second thoughts about that solution because it will always return a relative path from your working directory. If that works for you that's perfectly fine - however if it is an issue you could also do something more simple like this: size_t custom_join_paths(const char *path_a, const char *path_b, char *buffer,
size_t buffer_size)
{
if (cwk_path_is_absolute(path_b)) {
return cwk_path_normalize(path_b, buffer, buffer_size);
} else {
return cwk_path_join(path_a, path_b, buffer, buffer_size);
}
} The output will be normalized though, I hope that won't be an issue for you. I appreciate your input a lot! I will have to think about what to do relating to the library interface. |
Ah - I probably should've said this earlier, but my reasoning behind implicitly using the working directory was because I'd expect a lot of people would feed the output of the function straight into |
The behaviour of cwk_path_join should be similar to running
cd
on the first argument, andcd
on the last argument directly afterwards.We can see this works with simple statements, like joining together
hello
andworld
:Output of cwk_path_join:
hello/world
Output of os.path.join from Python:
hello/world
Output of two
cd
s:hello/world
But, if we try to do something more subtle, like joining together
/hello
and/world
, cwalk fails catastrophically:Output of cwk_path_join:
/hello/world
(See https://likle.github.io/cwalk/reference/cwk_path_join.html - This flaw is even demonstrated in the documentation!)Output of os.path.join from Python:
/world
Output of two
cd
s:/world
So, why is this happening? It seems that cwk_path_join doesn't actually "walk" or "separate cd" as it is intended to, but rather word-for-word smashes the two paths together.
Unless there is an alternative function that does this properly, cwk_path_join should NOT operate like this. Every argument to cwk_path_join should operate like a separate, sequenced cd.
If I run
cd /hello
and thencd /world
, I end up in/world
, because of the/
. I do not end up in/hello/world
. If I used/hello
and then./world
(or justworld
), it would be/hello/world
, but I did not do this.Unreliable behaviour of cwk_path_join makes this library completely unusable for many people. I would suggest testing your function against Python's os.path functions.
The text was updated successfully, but these errors were encountered: