diff --git a/.gitignore b/.gitignore index 496ad83..d1e7896 100644 --- a/.gitignore +++ b/.gitignore @@ -1,90 +1,12 @@ # ---> C -# Prerequisites -*.d - # Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch +build/ # Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib +lib/ # Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf - -# ---> C++ -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app +targets/ # ---> Gradle .gradle @@ -120,9 +42,6 @@ gradle-app.setting # Local History for Visual Studio Code .history/ -# Built Visual Studio Code Extensions -*.vsix - # ---> Bazel # gitignore template for Bazel build system # website: https://bazel.build/ @@ -137,4 +56,3 @@ gradle-app.setting /.ijwb/ /.aswb/ /.clwb/ - diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..37fe94d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "C_Cpp.default.cStandard": "c17" +} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..400a459 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +CFLAGS = -std=c17 +CPPFLAGS = -std=c++17 +APPS_DIR = ./apps +TARGETS_DIR = ./targets +OBJECTS_DIR = ./build +LIBS_DIR = ./src +INCLUDES = -I ./include +TESTS_DIR = ./tests +VPATH = $(TARGETS_DIR) $(OBJECTS_DIR) $(APPS_DIR) $(LIBS_DIR) $(TESTS_DIR) + +main: main.c requests.o + cc $(CFLAGS) $(INCLUDES) -lcurl $(APPS_DIR)/main.c $(LIBS_DIR)/requests.c -o $(TARGETS_DIR)/main + +requests.o: requests.c + $(CC) $(CFLAGS) $(INCLUDES) -c $(LIBS_DIR)/requests.c -o $(OBJECTS_DIR)/requests.o + +test: test_requests + $(TARGETS_DIR)/test_requests + +test_requests: test_requests.cpp requests.o + $(CXX) $(CPPFLAGS) $(INCLUDES) -lcurl -lgtest -lgtest_main $(TESTS_DIR)/test_requests.cpp $(OBJECTS_DIR)/requests.o -o $(TARGETS_DIR)/test_requests + +clean: + rm $(TARGETS_DIR)/* $(OBJECTS_DIR)/* diff --git a/README.md b/README.md index 2912c07..4459bdb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,14 @@ # c-rss -An RSS feed reader written in C \ No newline at end of file +An RSS feed reader written in C + +I am re-learning C by writing an RSS feed reader from scratch. I plan on playing around with several build tools such as make, gradle, and bazel. + +## Goals + +* get better at C +* get better at Makefiles +* learn how to write gradle plugins +* get better at SQL +* compare make, gradle, and bazel +* learn how to use gtest for C projects diff --git a/apps/main.c b/apps/main.c new file mode 100644 index 0000000..4bf85e2 --- /dev/null +++ b/apps/main.c @@ -0,0 +1,11 @@ +#include +#include + +#include "requests.h" + +int main(void) { + printf("Hello, world!\n"); + requestInit(); + requestGet("https://google.com"); + requestCleanup(); +} \ No newline at end of file diff --git a/include/requests.h b/include/requests.h new file mode 100644 index 0000000..37838f2 --- /dev/null +++ b/include/requests.h @@ -0,0 +1,28 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __SHILLERBEN_REQUESTS__ +#define __SHILLERBEN_REQUESTS__ + +typedef struct GetRequestResult GetRequestResult; +struct GetRequestResult { + int errorCode; + size_t size; + size_t capacity; + char *data; +}; + +void requestsInit(void); +void requestsCleanup(void); +GetRequestResult requestGet(const char* url); + +size_t _getRequestCb(char *buffer, size_t size, size_t nmemb, GetRequestResult *result); + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/src/requests.c b/src/requests.c new file mode 100644 index 0000000..35e6aec --- /dev/null +++ b/src/requests.c @@ -0,0 +1,73 @@ +#include +#include +#include + +#include + +#include "requests.h" + +void requestsInit(void) { + curl_global_init(CURL_GLOBAL_DEFAULT); +} + +void requestsCleanup(void) { + curl_global_cleanup(); +} + +GetRequestResult requestGet(const char* url) { + printf("requestGet(%s)\n", url); + + GetRequestResult result = { + .errorCode = -1, + .data = NULL, + }; + + CURL *handle = curl_easy_init(); + CURLcode err; + + err = curl_easy_setopt(handle, CURLOPT_URL, url); + if (err) { + printf("Failed to set url\n"); + return result; + } + err = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, _getRequestCb); + if (err) { + printf("Failed to set callback function\n"); + return result; + } + err = curl_easy_setopt(handle, CURLOPT_WRITEDATA, &result); + if (err) { + printf("Failed to set callback data\n"); + return result; + } + result.errorCode = 0; + result.size = 0; + result.capacity = 1024; + result.data = calloc(1024, sizeof(char)); + err = curl_easy_perform(handle); + if (err) { + printf("Error performing request\n"); + result.errorCode = -1; + result.size = 0; + free(result.data); + result.data = NULL; + return result; + } + return result; +} + +size_t _getRequestCb(char *buffer, size_t size, size_t nmemb, GetRequestResult *result) { + size_t numBytes = size * nmemb; + while (result->size + numBytes > result->capacity + 1 /*extra byte for null terminator*/) { + size_t newCapacity = result->capacity * 2; + char *newData = calloc(newCapacity, sizeof(char)); + memcpy(newData, result->data, result->size); + free(result->data); + result->data = newData; + result->capacity = newCapacity; + } + memcpy(result->data + result->size, buffer, numBytes); + result->size += numBytes; + result->data[result->size] = '\0'; + return numBytes; +} diff --git a/tests/test_requests.cpp b/tests/test_requests.cpp new file mode 100644 index 0000000..bfd1501 --- /dev/null +++ b/tests/test_requests.cpp @@ -0,0 +1,16 @@ +#include +#include + +#include "requests.h" + +TEST(RequestsTest, HttpsGetTest) { + requestsInit(); + std::string expected = "\n\n\nBen Shiller"; + for (int i = 0; i < 10; ++i) { + GetRequestResult result = requestGet("https://shillerben.com"); + // std::cout << "GET https://shillerben.com returned: " << result.data << '\n'; + ASSERT_EQ(strncmp(result.data, expected.c_str(), expected.size()), 0); + free(result.data); + } + requestsCleanup(); +}