Want a way to get current current working directory (or any directory) without resolving symlinks
Summary
Currently in what would appear to be all the routines in sysutils related to paths that return a path expand symlinks to absolute paths. https://www.freepascal.org/docs-html/rtl/sysutils/filenameroutines.html
ParamStr(0) is also affected by this. https://www.freepascal.org/docs-html/rtl/system/paramstr.html
This is not always desirable, as one may may want to use symlinks to either:
- make things consistent on different setups
- to shorten the complete absolute path
- make the path more applicable to what is currently being worked on.
When using Free Pascal since the symlinks appear to always be fully resolved and unwrapped, all the above desired features are lost that one might be trying to leverage from the use of symlinks.
Linux and other *nix do not care which path is presented at a low level as long as the underlying filesystem supports symlinks. The path with symlinks, or the resolved unwrapped absolute path, both work the same.
Since they both work the same, it would be useful to have the option to preserve symlinks.
When the current working directly is a path with symlinks it it, and Linux is queried for the current working directory, the symbolic path is returned, not the absolute path. Typically in languages like C/C++ an additional step needs to be done to resolve and unwrap the symbolic path and get the absolute path.
I'm not sure if this should be a bug report or a feature request. If addressed as a bug it would likely break existing expected functionality too much.
System Information
- Operating system: All Linux, and likely MacOS and FreeBSD, may be relevant to Windows as well
- Processor architecture: All
- Device: All
Example Project
The following C++ program and pascal programs act different in this regard.
What is desired in Free Pascal is functionality accessible in C/C++, but without linking to C libraries to achieve this.
getcurdirpas2.pas
program getcurdirpas2;
uses sysutils;
var
s: string;
begin
s := sysutils.getcurrentdir;
writeln ('Current directory is : ', s);
writeln ('"." expanded is ', expandFileName('.'));
writeln ('ParamStr(0) is ', ParamStr(0));
end.
getcurdircxx.cxx
#include <unistd.h>
#include <cstdio>
int main(int argc, char **argv) {
printf("Current working directory is: %s\n", get_current_dir_name());
printf("argv[0] is %s\n", argv[0]);
}
Ok, now for the prep.
$ cd /home/shared-development/
$ mkdir -pv abc/def/ghi
mkdir: created directory 'abc'
mkdir: created directory 'abc/def'
mkdir: created directory 'abc/def/ghi'
$ ln -sv abc/def/ghi jkl
'jkl' -> 'abc/def/ghi'
$ cd jkl
$ pwd
/home/shared-development/jkl
We are clearly in /home/shared-development/jkl
from a logical view.
Now from inside that directory, lets compare the differences between C++ and Free Pascal.
Starting with C++ (could as just as well been in C...):
$ clang++ -o getcurdircxx getcurdircxx.cxx
Mon 03Oct22 20:55:15 /home/shared-development/jkl
dwight@kala2206 $ ./getcurdircxx
Current working directory is: /home/shared-development/jkl
argv[0] is ./getcurdircxx
OK, correct for both current working directory and the first argument.
Now, with fpc
:
$ fpc getcurdirpas2
Free Pascal Compiler version 3.2.2 [2022/08/31] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling getcurdirpas2.pas
Linking getcurdirpas2
14 lines compiled, 0.1 sec
$ ./getcurdirpas2
Current directory is : /home/shared-development/abc/def/ghi
"." expanded is /home/shared-development/abc/def/ghi
ParamStr(0) is /home/shared-development/abc/def/ghi/getcurdirpas2
Expanding dot (.
) to the absolute path, that might be understandable...
But not always desirable...
But current working directory and ParamStr(0) are a bit more confusing.
Current working directory according the my shell
and C is what I expected it to be.
When someone is using a symbolic path they often want that to be the logical path, and understand another step is needed to get absolute path.
But this is where ParamStr(0) get even more confusing (from a Unix perspective):
$ ln -sv getcurdirpas2 someOtherSymbolicNameOfTheApp
'someOtherSymbolicNameOfTheApp' -> 'getcurdirpas2'
$ ./someOtherSymbolicNameOfTheApp
Current directory is : /home/shared-development/abc/def/ghi
"." expanded is /home/shared-development/abc/def/ghi
ParamStr(0) is /home/shared-development/abc/def/ghi/getcurdirpas2
So now ParamStr(0) does not match what I typed in from the command line. Technically the path given is correct, that is the absolute path of what was executed, but it is not the symbolic or logical name I assigned to the application.
So, not a bug per se, but confusing nonetheless from a Unix perspective.
But if one wanted to do what is common in Unix, use the symbolic name as an additional argument, that is not possible with ParamStr(0) converting the symbolic name to the absolute name.
Relevant 3rd party information
This all stemmed from this issue report filed by me and us coming to realization that what the was expected to be the case was not, and it was due to how Free Pascal is handling symbolic paths: CudaText Feature request: Add option to not unwrap symlinks when editing files or directories from the command line.