diff --git a/main.cpp b/main.cpp index c3fbad7..6651f29 100644 --- a/main.cpp +++ b/main.cpp @@ -1,16 +1,12 @@ #include -#include - -#include +#include #include #include -#include #include using json = nlohmann::json; -// used to have a dynamic string -typedef struct Response +struct Response { char *string; size_t size; @@ -23,12 +19,9 @@ struct TestCaseResponse }; size_t write_chunk(void *data, size_t size, size_t nmemb, void *userData); - void formatResponse(char *response); std::string FormatHTMLToString(const std::string &response); TestCaseResponse GetTestCases(const std::string &content); - -std::pair GetParamName(const std::string ¶m); void CreateJSON(json *response, const TestCaseResponse &testCases); int main() @@ -37,60 +30,36 @@ int main() std::cout << "Enter Leetcode question name: " << std::endl; std::cin >> questionName; - CURL *curl; - CURLcode result; - - // Initialize CURL - curl = curl_easy_init(); + CURL *curl = curl_easy_init(); if (curl == nullptr) { std::cerr << "HTTP REQUEST FAILED: curl_easy_init() failed!" << std::endl; return -1; } - else - { - std::cout << "Curl initialized successfully!" << std::endl; - } Response response; response.string = (char *)malloc(1); response.size = 0; - // Set options for the HTTP request - curl_easy_setopt(curl, CURLOPT_URL, - "https://leetcode.com/graphql"); + curl_easy_setopt(curl, CURLOPT_URL, "https://leetcode.com/graphql"); - // Set Post data (like JSON body) to match leetcode graph ql query json query = { {"query", "query questionData($titleSlug: String!) { question(titleSlug: $titleSlug) { title content difficulty topicTags { name } hints } }"}, - {"variables", { - {"titleSlug", questionName} // This can now be easily modified - }}}; + {"variables", {{"titleSlug", questionName}}}}; const std::string postData = query.dump(); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str()); - // Set headers for JSON data struct curl_slist *headers = nullptr; headers = curl_slist_append(headers, "Content-Type: application/json"); - std::string referer = "Referrer: https://leetcode.com/problems/" + questionName + "/"; headers = curl_slist_append(headers, referer.c_str()); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - /** - * WriteFunction allows for specifying a callback function - * Curl_easy_perfrom will call this function repeatedly - * Each time it is called the pointer is passed to a new chunk of response - * string - */ - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_chunk); - // Address of response string is passed in write_chunk as userData + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_chunk); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); - // Perform the HTTP request - result = curl_easy_perform(curl); + CURLcode result = curl_easy_perform(curl); if (result != CURLE_OK) { std::cerr << "Error: " << curl_easy_strerror(result) << std::endl; @@ -100,49 +69,30 @@ int main() formatResponse(response.string); free(response.string); - // Cleanup curl_easy_cleanup(curl); return 0; } -// returns number of bytes in the chunk -// data is set to a ptr that points to block of data recieved in this chunk -// nmemb is the number of bytes in the block of data -// userData points to what we want (points to where the response string is stored) size_t write_chunk(void *data, size_t size, size_t nmemb, void *userData) { - // size is always 1 size_t real_size = size * nmemb; - Response *response = (Response *)userData; - // allocate more space for chunk that was recieved - // response->size is size of existing mem and real_size is the size recieved and +1 accounts for null - char *ptr = (char *)realloc(response->string, response->size + real_size + 1); + char *ptr = (char *)realloc(response->string, response->size + real_size + 1); if (ptr == nullptr) { - std::cerr << "Problem reallocating space for chunk recieved" << std::endl; + std::cerr << "Problem reallocating space for chunk received" << std::endl; return 0; } - // set response string to the new (larger) memory address + response->string = ptr; - // append new porition onto existing string memcpy(&(response->string[response->size]), data, real_size); - // update strings size response->size += real_size; - // append null character response->string[response->size] = '\0'; + return real_size; } -/** - * Returns a map containing the following tags stored as keys - * and their description as their value. - * - * title content difficulty topicTags { name } hints - * - * Assumes json response will use the tags in the given order above. - */ void formatResponse(char *response) { std::vector currentTags = {"title", "content", "difficulty", "topicTags", "hints"}; @@ -178,7 +128,6 @@ void formatResponse(char *response) if (question.contains(tag)) { question[tag] = FormatHTMLToString(question[tag]); - // Get testcases from given content if (tag == "content") { testCases = GetTestCases(question[tag]); @@ -195,7 +144,6 @@ void formatResponse(char *response) } } -// check for tag std::string FormatHTMLToString(const std::string &response) { int i = 0; @@ -203,7 +151,6 @@ std::string FormatHTMLToString(const std::string &response) while (i < response.length()) { - // check for HTML elements if (response[i] == '<') { while (response[i] != '>') @@ -214,7 +161,6 @@ std::string FormatHTMLToString(const std::string &response) continue; } - // check for < (<) , > (>); if (i < response.length() - 4 && (response.substr(i, 4) == "<" || response.substr(i, 4) == ">")) { std::string expression = response.substr(i, 4); @@ -230,7 +176,6 @@ std::string FormatHTMLToString(const std::string &response) continue; } - // check for & (&) if (i < response.length() - 5 && (response.substr(i, 5) == "&")) { result += "&"; @@ -238,22 +183,18 @@ std::string FormatHTMLToString(const std::string &response) continue; } - // check for 's if (i < response.length() - 6 && response.substr(i, 6) == "'s") { i += 6; continue; } - // check for   tags if (i < response.length() - 6 && response.substr(i, 6) == " ") { i += 6; continue; } - // check for multiple whitespace characters - // want to keep 1 where there are multiple if (response[i] == '\n') { result += "\n"; @@ -281,11 +222,6 @@ std::string FormatHTMLToString(const std::string &response) return result; } -/** - * Basic test cases given by leetcode are given in a string of the form. Example case & output. - * Should always be at least 2 test cases given. - * @returns array of oxpected outputs for the test cases. - */ TestCaseResponse GetTestCases(const std::string &content) { TestCaseResponse tests; @@ -339,7 +275,6 @@ TestCaseResponse GetTestCases(const std::string &content) { tests.testCaseParams.push_back({paramName, paramRes}); } - // std::cout << paramName << " " << paramRes << std::endl; } if (i <= content.length() - 6 && content.substr(i, 6) == "Output") @@ -371,7 +306,6 @@ TestCaseResponse GetTestCases(const std::string &content) void CreateJSON(json *response, const TestCaseResponse &tests) { - // filter out invalid characters from title std::string title = (*response)["title"]; const std::string invalid_chars = "\\/:*?\"<>|"; for (char c : invalid_chars) @@ -380,9 +314,7 @@ void CreateJSON(json *response, const TestCaseResponse &tests) } std::string jsonName = "../../../Questions/" + title + ".txt"; - std::ofstream outputJSON; - outputJSON.open(jsonName); - // should have to create the file so always should open + std::ofstream outputJSON(jsonName); if (!outputJSON.is_open()) { std::cerr << "Error creating output file for JSON response" << std::endl; @@ -390,25 +322,20 @@ void CreateJSON(json *response, const TestCaseResponse &tests) } outputJSON << "{\n"; - // iterates through json response inserting key and value as pair into output file for (auto it = (*response).begin(); it != (*response).end(); ++it) { outputJSON << "\"" << it.key() << "\"" << ": " << it.value() << ',' << "\n"; } - // handle situation where testCases might not generate - - // Insert testcases outputJSON << "\"testCases\"" << ": [" << "\n"; int j = 0; int size = tests.testCases.size(); for (int i = 0; i < size; i++) { - // start inserting new object into array inside json file outputJSON << "{\n"; - std::string expectedResult = tests.testCases[i]; // testcase expected outputs + std::string expectedResult = tests.testCases[i]; outputJSON << "\"expectedResult\": " << "\"" << expectedResult << "\",\n"; int numParams = tests.testCaseParams.size() / tests.testCases.size(); @@ -425,7 +352,6 @@ void CreateJSON(json *response, const TestCaseResponse &tests) } } - // if i is at the end then we need to close off the obj if (i == size - 1) { outputJSON << "}\n"; @@ -440,35 +366,4 @@ void CreateJSON(json *response, const TestCaseResponse &tests) outputJSON << "}"; outputJSON.close(); -} - -/** - * params are taken from the json as a string containing 'paramName'='param' - * This function splits the paramName and param seperately to label them in the output JSON easier. - * (the problem function calls explicility used by the users will contain the same paramNames so makes using them easier as well) - */ -std::pair GetParamName(const std::string ¶m) -{ - std::string paramName = ""; - std::string paramResult = ""; - bool nameParsed = false; - for (int i = 0; i < param.length(); i++) - { - - if (param[i] == '=') - { - nameParsed = true; - continue; - } - - if (param[i] != ' ' && !nameParsed) - { - paramName += param[i]; - } - else if (param[i] != ' ' && nameParsed) - { - paramResult += param[i]; - } - } - return {paramName, paramResult}; } \ No newline at end of file