I am writing a program to make copies of files in Linux. The program takes two arguments:
- a
char *source
which is the path to the source file that needs copying - a
char *dest
which is the path to the destination where a copy ofsource
will be made
I am using the fopen(3) function to open files.
So far i have noticed fopen() does not recognize common bash shell expansions such as:
~
for current users home directory
To handle this i could use switch/if statements and check if the source path (char *source
) has any of the characters and act accordingly. This solution would mean i would have to construct a absolute path (a path from /
aka the root directory example: /usr/dir2/books/maths.pdf/
). Ideally i would like a solution that works on any path from any current working directory the user is in.
My question is: Is there a better way to handle this? How could i handle the paths in a portable and efficient manner?
CodePudding user response:
So far i have noticed
fopen()
does not recognize common bash shell expansions
Indeed it does not. shell expansions such as tilde substitution and globbing are performed by the shell. If you want them to be performed by your program, too, then you need to implement that yourself. On the flip side, you do not need to worry about quoting characters that would otherwise be significant to the shell, because you don't get word splitting etc. except if and as you implement it.
Is there a better way to handle this? How could i handle the paths in a portable and efficient manner?
A pretty good way to handle it would be to let somebody else handle it. In particular, if the filenames in question are specified as command-line arguments, then expansions will be handled (or not) by the shell, under control of the user. In that case, users will not expect your program to perform additional expansions. If the file names come from another source (config file, file chooser) then it is reasonable to expect the full path or possibly a correct relative path to be given.
If you nevertheless want to handle bash-style expansion of a bare tilde in particular, then that's not so hard. It applies only to tildes appearing as the first character of a file name, and it expands those to the value of environment variable HOME
. You can read environment variables with getenv()
, and other than that you just need some relatively simple string manipulation.
More general tilde expansion, where ~username
appearing at the beginning of a filename is expanded to the home directory of user username
, would require you to consult the user (a.k.a. password) database. On a POSIX system, a natural way to do that would be via the getpwnam()
function.
Note well that different shells exhibit differences in the expansions they perform and the conditions under which they perform them. You cannot emulate all shells at the same time, so leaving expansions an external concern is both the most portable and the most efficient option.
CodePudding user response:
Consider using wordexp to convert an input string to list of files, based on bash expansion.
See man wordexp https://man7.org/linux/man-pages/man3/wordexp.3.html
Not very efficient, as it fork a shell to perform the expansion, but does the job.