I’m stuck on Stage #NI 5
I’ve tried commenting out all the irrelevant sections of the code. The change I made was with the way argc and argv are parsed. Furthermore, I can’t replicate the eror when I compile it myself. This is what happens when I run myself:
vestatian@pegasus:~/codecrafters/codecrafters-shell-c$ gcc app/main.c && ./a.out
$ echo 'example shell'
example shell
$
Here are my logs:
vestatian@pegasus:~/codecrafters/codecrafters-shell-c$ codecrafters test
Initiating test run...
⚡ This is a turbo test run. https://codecrafters.io/turbo
Running tests. Logs should appear shortly...
[compile] Moved ./.codecrafters/run.sh → ./your_program.sh
[compile] Compilation successful.
Debug = true
[tester::#NI6] Running tests for Stage #NI6 (Quoting - Single quotes)
[tester::#NI6] [setup] export PATH=/tmp/blueberry/orange/mango:$PATH
[tester::#NI6] Running ./your_program.sh
[tester::#NI6] [setup] echo -n "pineapple mango." > "/tmp/bar/f 84"
[tester::#NI6] [setup] echo -n "grape mango." > "/tmp/bar/f 76"
[tester::#NI6] [setup] echo -n "pineapple apple." > "/tmp/bar/f 6"
[your-program] $ echo 'test script'
[your-program] execvp failed
[tester::#NI6] Output does not match expected value.
[tester::#NI6] Expected: "test script"
[tester::#NI6] Received: "execvp failed"
[your-program] : Bad address
[your-program] $
[tester::#NI6] Assertion failed.
[tester::#NI6] Test failed
Below is the modified code: Before this, no errors were being thrown at all; originally, this code just used strtok with ’ ’ delimiter to get argc and argv.
void function_parse_input(int argc, char **argv, char *input) {
char **argv_i = (char**)malloc(sizeof(char*) * (argc + 1));
bool in_quotes = false;
bool in_delimiter = true;
int len = strlen(input) + 1;
// printf("Initial input: %s\n", input);
for (int i = 0; i < len; i++) {
// printf("%d | Processing: %c | ", i, input[i]);
if (input[i] == '\'') {
in_quotes = in_quotes ? false : true;
strcpy(input + i, input + i + 1);
len--;
i--;
// printf("toggled quotes\n");
}
else if (!in_quotes && input[i] == ' ') {
in_delimiter = true;
input[i] = '\0';
// printf("delimiter added\n");
}
else if (input[i] != '\0') {
if (in_delimiter) {
in_delimiter = false;
argv_i = (char**)realloc(argv_i, sizeof(char*) * (argc + 1));
argv_i[argc++] = &input[i];
// printf("Added argv[%d]: index %d (addr %p) | ", argc - 1, i, argv_i[argc - 1]);
}
}
}
for (int i = 0; i < argc; i++) {
argv[i] = argv_i[i];
// printf("argv[%d]: %s (addr %p)\n", i, argv[i], argv_i[i]);
}
free(argv_i);
}
This is my main function:
int main() {
setbuf(stdout, NULL);
while (1) {
char input[BUFFERSIZE_INPUT];
int argc = 0;
char *argv[BUFFERSIZE_ARGV];
printf("$ ");
fgets(input, BUFFERSIZE_INPUT, stdin);
input[strlen(input) - 1] = '\0';
function_parse_input(argc, argv, input);
if (strcmp(argv[0], "exit") == 0 && argv[1][0] == '0') {
return 0;
}
else if (strcmp(argv[0], "type") == 0) {
builtin_type(argv[1]);
}
else if (strncmp(argv[0], "echo ", 5) == 0) {
builtin_echo(argc, argv);
}
else if (strcmp(argv[0], "pwd") == 0) {
builtin_pwd();
}
else if (strcmp(argv[0], "cd") == 0) {
builtin_cd(argv[1]);
}
else {
char valid_path[BUFFERSIZE_PATH];
if (function_search_path(argv[0], valid_path) == 0) {
builtin_execute(valid_path, argv);
} else {
printf("%s: command not found\n", argv[0]);
}
}
}
}
This is where execvp failed
comes from:
void builtin_execute (char *path, char **argv) {
pid_t pid = fork();
if (pid == EXIT_SUCCESS) {
execvp(path, argv);
perror("execvp failed\n");
exit(1);
}
else if (pid < 0) {
perror("fork failed\n");
}
else {
int status;
waitpid(pid, &status, 0);
}
}