How can we implement the cd command in c that support ~, .., -
I write the following code:
void exec_cd(char* command) {
if (chdir(command) != 0) {
perror("chdir failed");
}
if (!strcmp(command, "~")) {
chdir(getenv("HOME"));
}
if (!strcmp(command, "/")) {
// do stuff
}
if (!strcmp(command, "-")) {
// do stuff
}
if (!strcmp(directory, "..")) {
chdir("..");
}
}
How can we implement ~ and -
and the ..
command is correct?
chdir
will change the current directory of your program, probably a command shell you are trying to implement.
Absolute and relative paths such as /
, ..
, subdir
pose no problem and can be passed directly to the chdir
system call.
-
is a special argument for the cd
command: cd -
means to go back to the previous current directory. To implement this functionality, you need to keep track of the last directory cd
changed to. Use the getcwd()
function for that before calling chdir
and if successful, keep this previous directory in a global array.
~
is another special thing: it should be expanded to the home directory (the value of the HOME
environment variable) before dispatching to the command handler, so one can type cd ~
, or just cd
to change to the home directory but cd "~"
to change to a directory named "~"
. ~
should expand to $(HOME)
, either as a stand alone string or as the initial portion of a path: ~/bin
. Note that ~name
should expand to the home directory of the user name
.
Here is a partial and simplistic version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
char lastdir[MAX_PATH]; // initialized to zero
int exec_cd(char *arg) {
char curdir[MAX_PATH];
char path[MAX_PATH];
if (getcwd(curdir, sizeof curdir)) {
/* current directory might be unreachable: not an error */
*curdir = '\0';
}
if (arg == NULL) {
arg = getenv("HOME");
}
if (!strcmp(arg, "-")) {
if (*lastdir == '\0') {
fprintf(stderr, "no previous directory\n");
return 1;
}
arg = lastdir;
} else {
/* this should be done on all words during the parse phase */
if (*arg == '~') {
if (arg[1] == '/' || arg[1] == '\0') {
snprintf(path, sizeof path, "%s%s", getenv("HOME"), arg + 1);
arg = path;
} else {
/* ~name should expand to the home directory of user with login `name`
this can be implemented with getpwent() */
fprintf(stderr, "syntax not supported: %s\n", arg);
return 1;
}
}
}
if (chdir(arg)) {
fprintf(stderr, "chdir: %s: %s\n", strerror(errno), path);
return 1;
}
strcpy(lastdir, curdir);
return 0;
}