I’m stuck on Stage #MG5 in “Build your own shell”, where the task is to find an executable in PATH.
The error log is:
remote: [tester::#MG5] Running tests for Stage #MG5 (The type builtin: executable files)
remote: [tester::#MG5] Running ./your_program.sh
remote: [tester::#MG5] Expected prompt ("$ ") to be printed, got ""
remote: [tester::#MG5] Test failed
Here is the code:
// ...
int main() {
// parse PATH
const char* path_raw = getenv("PATH");
if (path_raw != nullptr) {
std::string path_str = path_raw;
split(&PATH, path_str, PATH_DELIMITER);
}
// map command names to functions
BUILTIN_FUNCTIONS["echo"] = [](std::string input){
__builtin_echo(input);
};
BUILTIN_FUNCTIONS["type"] = [](std::string input){
__builtin_type(input);
};
// Flush after every std::cout / std:cerr
// Note: I tried removing also this
std::cout << std::unitbuf;
std::cerr << std::unitbuf;
// REPL
while (true) {
std::cout << "$ "; // here is the $...
std::string input, command, command_args;
std::getline(std::cin, input);
if (input.compare(0, 4, "exit") == 0)
break;
command = input.substr(0, input.find(" "));
command_args = input.substr(input.find(" ")+1);
if (BUILTIN_FUNCTIONS.count(command))
BUILTIN_FUNCTIONS[command](command_args);
else
std::cout << input << ": command not found" << std::endl;
}
}
Note: I tried setting debug to true in codecrafters.yml, the log is still the same.
The reason isn’t clear, since it previously worked. I tried reverting some changes I made in the code (for example using macros to define the delimiter “;” or “:” based on OS), however it still doesn’t work.
Running codecrafters test --previous gaves me the same result (failed).
To debug it I commented out the first section of the code where I initialized the PATH vector and BUILTIN_FUNCTIONS map. After some trials I found that the issue is caused by the split function.
Here is the interested section of the code:
#if __linux__
const char *PATH_DELIMITER = ":";
const char *PATH_SEPARATOR = "/";
#elif _WIN32
const char *PATH_DELIMITER = ";";
const char *PATH_SEPARATOR = "\\";
#else
const char *PATH_DELIMITER = ":";
const char *PATH_SEPARATOR = "/";
#endif
// define PATH at compile time, but populate at program start.
// Note: std::vector is a dynamic array
std::vector<std::string> PATH;
// ...
void split(
std::vector<std::string> *vec_ptr,
std::string str,
const char *delimiter
){
int start = 0, end;
while (start < str.size()){
end = str.find(delimiter, start+1) + 1;
vec_ptr->push_back(str.substr(start, end - start - 1));
start = end;
}
}
If I do the following I do not get any errors:
size_t start = 0, end;
while (start < str.size()){
end = str.size();
// end = str.find(delimiter, start+1) + 1;
// vec_ptr->push_back(str.substr(start, end - start - 1));
start = end;
}
The moment I use end = str.find(...) I get the error.
To be honest, I’m not entirely sure, as my C++ is a bit rusty. However, I believe you can try std::getline, rather than rolling your own split function: