-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9b853db
commit d97df98
Showing
4 changed files
with
151 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"configurations": [ | ||
{ | ||
"name": "Mac", | ||
"includePath": [ | ||
"${workspaceFolder}/**" | ||
], | ||
"defines": [], | ||
"macFrameworkPath": [ | ||
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks" | ||
], | ||
"compilerPath": "/usr/local/bin/g++-13", | ||
"cStandard": "c17", | ||
"cppStandard": "c++17", | ||
"intelliSenseMode": "macos-clang-x64" | ||
} | ||
], | ||
"version": 4 | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,150 @@ | ||
#include <cstdlib> // for system() | ||
#include <cstring> // for strcmp() | ||
#include <cstdlib> // for system() | ||
#include <cstring> // for strcmp() | ||
#include <dirent.h> // for opendir(), readdir(), closedir() | ||
#include <iostream> // for std::cin, std::cout | ||
#include <readline/history.h> | ||
#include <readline/readline.h> | ||
#include <sstream> // for std::istringstream | ||
#include <string> // for std::string, std::getline | ||
#include <string> // for std::string, std::getline | ||
#include <vector> | ||
|
||
class CommandLineInterface { | ||
public: | ||
void run() { | ||
while (true) { | ||
std::cout << "> "; | ||
std::string line; | ||
if (!std::getline(std::cin, line)) { | ||
break; | ||
} | ||
if (line.empty()) { | ||
continue; | ||
} | ||
if (line == "quit" || line == "exit") { | ||
break; | ||
} | ||
std::string command; | ||
std::string assignment; | ||
if (!parse_command_line(line, command, assignment)) { | ||
continue; | ||
} | ||
if (command == "-m" || command == "--multi-grader") { | ||
run_multi_grader(assignment); | ||
} else { | ||
std::cerr << "myprogram: invalid command\n"; | ||
print_help(); | ||
} | ||
} | ||
CommandLineInterface() { | ||
// Initialize Readline library | ||
rl_attempted_completion_function = completion; | ||
} | ||
|
||
void run() { | ||
while (true) { | ||
// Use Readline to read user input with tab completion | ||
char *input = readline("> "); | ||
if (!input) { | ||
break; | ||
} | ||
std::string line(input); | ||
free(input); | ||
|
||
if (line.empty()) { | ||
continue; | ||
} | ||
if (line == "quit" || line == "exit") { | ||
break; | ||
} | ||
std::string command; | ||
std::string assignment; | ||
if (!parse_command_line(line, command, assignment)) { | ||
continue; | ||
} | ||
if (command == "-m" || command == "--multi-grader") { | ||
run_multi_grader(assignment); | ||
} else { | ||
std::cerr << "myprogram: invalid command\n"; | ||
print_help(); | ||
} | ||
} | ||
} | ||
|
||
private: | ||
void print_help() const { | ||
std::cout << "Usage: myprogram [options]\n"; | ||
std::cout << "\n"; | ||
std::cout << "Options:\n"; | ||
std::cout << " -h, --help Show this help message and exit\n"; | ||
std::cout << " -m, --multi-grader ASSIGNMENT\n"; | ||
std::cout << " Grade the specified assignment using multi-grader\n"; | ||
static char **completion(const char *text, int start, int end) { | ||
// Generate completion matches | ||
rl_attempted_completion_over = 1; | ||
return rl_completion_matches(text, generator); | ||
} | ||
|
||
static char *generator(const char *text, int state) { | ||
static int index; | ||
static std::vector<std::string> matches; | ||
|
||
if (state == 0) { | ||
index = 0; | ||
matches.clear(); | ||
|
||
// Check if the user is entering the ASSIGNMENT argument | ||
if (rl_point > 0 && rl_line_buffer[rl_point - 1] == ' ') { | ||
// Generate a list of possible directory completion matches | ||
std::string path(text); | ||
std::size_t pos = path.find_last_of('/'); | ||
if (pos != std::string::npos) { | ||
path = path.substr(0, pos + 1); | ||
} else { | ||
path.clear(); | ||
} | ||
DIR *dir = opendir(path.empty() ? "." : path.c_str()); | ||
if (dir) { | ||
struct dirent *entry; | ||
while ((entry = readdir(dir)) != nullptr) { | ||
if (entry->d_type == DT_DIR && | ||
std::strncmp(text + path.size(), entry->d_name, | ||
strlen(text) - path.size()) == 0) { | ||
matches.push_back(path + entry->d_name); | ||
} | ||
} | ||
closedir(dir); | ||
} | ||
} else { | ||
// Generate a list of possible command completion matches | ||
if (std::strncmp(text, "-m", strlen(text)) == 0) { | ||
matches.push_back("-m"); | ||
} | ||
if (std::strncmp(text, "--multi-grader", strlen(text)) == 0) { | ||
matches.push_back("--multi-grader"); | ||
} | ||
} | ||
} | ||
|
||
void run_multi_grader(const std::string& assignment) const { | ||
std::string command = "./multi-grader.sh "; | ||
command += assignment; | ||
system(command.c_str()); | ||
if (index < matches.size()) { | ||
return strdup(matches[index++].c_str()); | ||
} else { | ||
return nullptr; | ||
} | ||
} | ||
|
||
bool parse_command_line(const std::string& line, std::string& command, std::string& assignment) const { | ||
command.clear(); | ||
assignment.clear(); | ||
std::istringstream iss(line); | ||
std::string arg; | ||
while (iss >> arg) { | ||
if (arg == "-h" || arg == "--help") { | ||
print_help(); | ||
return false; | ||
} else if (arg == "-m" || arg == "--multi-grader") { | ||
command = arg; | ||
if (iss >> arg) { | ||
assignment = arg; | ||
} else { | ||
std::cerr << "myprogram: option requires an argument -- 'm'\n"; | ||
return false; | ||
} | ||
} else { | ||
std::cerr << "myprogram: unrecognized option '" << arg << "'\n"; | ||
return false; | ||
} | ||
void print_help() const { | ||
std::cout << "Usage: myprogram [options]\n"; | ||
std::cout << "\n"; | ||
std::cout << "Options:\n"; | ||
std::cout << " -h, --help Show this help message and exit\n"; | ||
std::cout << " -m, --multi-grader ASSIGNMENT\n"; | ||
std::cout << " Grade the specified assignment using " | ||
"multi-grader\n"; | ||
} | ||
|
||
void run_multi_grader(const std::string &assignment) const { | ||
std::string command = "./multi-grader.sh "; | ||
command += assignment; | ||
system(command.c_str()); | ||
} | ||
|
||
bool parse_command_line(const std::string &line, std::string &command, | ||
std::string &assignment) const { | ||
command.clear(); | ||
assignment.clear(); | ||
std::istringstream iss(line); | ||
std::string arg; | ||
while (iss >> arg) { | ||
if (arg == "-h" || arg == "--help") { | ||
print_help(); | ||
return false; | ||
} else if (arg == "-m" || arg == "--multi-grader") { | ||
command = arg; | ||
if (iss >> arg) { | ||
assignment = arg; | ||
} else { | ||
std::cerr << "myprogram: option requires an argument -- 'm'\n"; | ||
return false; | ||
} | ||
return true; | ||
} else { | ||
std::cerr << "myprogram: unrecognized option '" << arg << "'\n"; | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
}; | ||
|
||
int main() { | ||
CommandLineInterface cli; | ||
cli.run(); | ||
return 0; | ||
CommandLineInterface cli; | ||
cli.run(); | ||
return 0; | ||
} |