summaryrefslogtreecommitdiff
path: root/src/unix
diff options
context:
space:
mode:
authorAldrik Ramaekers <aldrikboy@gmail.com>2024-03-10 12:32:01 +0100
committerAldrik Ramaekers <aldrikboy@gmail.com>2024-03-10 12:32:01 +0100
commit7cc519c9d2f5b68aae04d368077f17c605009b43 (patch)
tree3d02133184e0ff2b5277cca46c2b61ed3b648c81 /src/unix
parent22f40608ec8ba81577625bb65043cacbc51710eb (diff)
fix config loading on osx, merge /linux and /osx
Diffstat (limited to 'src/unix')
-rw-r--r--src/unix/main_unix.cpp318
-rw-r--r--src/unix/mutex.cpp121
2 files changed, 439 insertions, 0 deletions
diff --git a/src/unix/main_unix.cpp b/src/unix/main_unix.cpp
new file mode 100644
index 0000000..8fdbc1b
--- /dev/null
+++ b/src/unix/main_unix.cpp
@@ -0,0 +1,318 @@
+#include "imgui.h"
+#include "imgui_spectrum.h"
+#include "imgui_impl_glfw.h"
+#include "imgui_impl_opengl3.h"
+#include "../utf8.h"
+#include "platform.h"
+#include "mutex.h"
+#include "array.h"
+#include "memory_bucket.h"
+#include "image.h"
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#define GL_SILENCE_DEPRECATION
+#if defined(IMGUI_IMPL_OPENGL_ES2)
+#include <GLES2/gl2.h>
+#endif
+#include <GLFW/glfw3.h> // Will drag system OpenGL headers
+
+void ts_create_gui(int window_w, int window_h);
+void ts_load_images();
+void ts_init();
+
+bool program_running = true;
+
+char config_path[MAX_INPUT_LENGTH];
+static const char* _ts_platform_get_config_file_path(char* buffer) {
+#ifdef __APPLE__
+ char* env = getenv("HOME");
+ char path_buf[MAX_INPUT_LENGTH];
+ snprintf(path_buf, MAX_INPUT_LENGTH, "%s%s", env, "/Library/Application Support/text-search");
+ snprintf(buffer, MAX_INPUT_LENGTH, "%s%s", path_buf, "/imgui.ini");
+
+ if (!ts_platform_dir_exists(path_buf)) {
+
+ mkdir(path_buf, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ }
+ return buffer;
+#else
+ char* env = getenv("HOME");
+ char path_buf[MAX_INPUT_LENGTH];
+ snprintf(path_buf, MAX_INPUT_LENGTH, "%s%s", env, "/text-search/");
+ snprintf(buffer, MAX_INPUT_LENGTH, "%.*s%s", MAX_INPUT_LENGTH-10, path_buf, "imgui.ini");
+ printf();
+ if (!ts_platform_dir_exists(path_buf)) {
+ mkdir(path_buf, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ }
+ return buffer;
+#endif
+}
+
+static void glfw_error_callback(int error, const char* description)
+{
+ fprintf(stderr, "GLFW Error %d: %s\n", error, description);
+}
+
+// Main code
+int main(int, char**)
+{
+ glfwSetErrorCallback(glfw_error_callback);
+ if (!glfwInit())
+ return 1;
+
+ // Decide GL+GLSL versions
+#if defined(IMGUI_IMPL_OPENGL_ES2)
+ // GL ES 2.0 + GLSL 100
+ const char* glsl_version = "#version 100";
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
+ glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
+#elif defined(__APPLE__)
+ // GL 3.2 + GLSL 150
+ const char* glsl_version = "#version 150";
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
+#else
+ // GL 3.0 + GLSL 130
+ const char* glsl_version = "#version 130";
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
+ //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
+ //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only
+#endif
+
+ // Create window with graphics context
+ GLFWwindow* window = glfwCreateWindow(1280, 720, "Text-Search", nullptr, nullptr);
+ if (window == nullptr)
+ return 1;
+ glfwMakeContextCurrent(window);
+ glfwSwapInterval(1); // Enable vsync
+
+ IMGUI_CHECKVERSION();
+ ImGui::CreateContext();
+ ImGuiIO& io = ImGui::GetIO(); (void)io;
+ io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
+ io.IniFilename = _ts_platform_get_config_file_path(config_path);
+
+ // Setup Platform/Renderer backends
+ ImGui_ImplGlfw_InitForOpenGL(window, true);
+ ImGui_ImplOpenGL3_Init(glsl_version);
+
+ // Setup Dear ImGui style
+ ImGui::Spectrum::StyleColorsSpectrum();
+ ImGui::Spectrum::LoadFont(18.0f);
+
+ ts_init();
+ ts_load_images();
+ ts_load_config();
+
+ ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
+ int display_w, display_h;
+ while (!glfwWindowShouldClose(window))
+ {
+ glfwPollEvents();
+
+ ImGui_ImplOpenGL3_NewFrame();
+ ImGui_ImplGlfw_NewFrame();
+ ImGui::NewFrame();
+
+ ts_create_gui(display_w, display_h);
+
+ // Rendering
+ ImGui::Render();
+ glfwGetFramebufferSize(window, &display_w, &display_h);
+ glViewport(0, 0, display_w, display_h);
+ glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
+ glClear(GL_COLOR_BUFFER_BIT);
+ ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
+
+ glfwSwapBuffers(window);
+ }
+
+ // Cleanup
+ ImGui_ImplOpenGL3_Shutdown();
+ ImGui_ImplGlfw_Shutdown();
+ ImGui::DestroyContext();
+
+ glfwDestroyWindow(window);
+ glfwTerminate();
+
+ return 0;
+}
+
+bool ts_platform_dir_exists(utf8_int8_t* path) {
+ DIR* dir = opendir(path);
+ if (dir) {
+ /* Directory exists. */
+ closedir(dir);
+ return true;
+ } else if (ENOENT == errno) {
+ return false; // does not exist
+ } else {
+ return false; // error opening dir
+ }
+}
+
+ts_file_content ts_platform_read_file(char *path, const char *mode) {
+ ts_file_content result;
+ result.content = 0;
+ result.content_length = 0;
+ result.file_error = 0;
+
+ FILE *file = fopen(path, mode);
+
+ if (!file)
+ {
+ if (errno == EMFILE)
+ result.file_error = FILE_ERROR_TOO_MANY_OPEN_FILES_PROCESS;
+ else if (errno == ENFILE)
+ result.file_error = FILE_ERROR_TOO_MANY_OPEN_FILES_SYSTEM;
+ else if (errno == EACCES)
+ result.file_error = FILE_ERROR_NO_ACCESS;
+ else if (errno == EPERM)
+ result.file_error = FILE_ERROR_NO_ACCESS;
+ else if (errno == ENOENT)
+ result.file_error = FILE_ERROR_NOT_FOUND;
+ else if (errno == ECONNABORTED)
+ result.file_error = FILE_ERROR_CONNECTION_ABORTED;
+ else if (errno == ECONNREFUSED)
+ result.file_error = FILE_ERROR_CONNECTION_REFUSED;
+ else if (errno == ENETDOWN)
+ result.file_error = FILE_ERROR_NETWORK_DOWN;
+ else if (errno == ESTALE)
+ result.file_error = FILE_ERROR_STALE;
+ else
+ {
+ result.file_error = FILE_ERROR_GENERIC;
+ }
+
+ return result;
+ }
+
+ fseek(file, 0 , SEEK_END);
+ int length = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ int length_to_alloc = length+1;
+
+ result.content = malloc(length_to_alloc);
+ if (!result.content) {
+ fclose(file);
+ return result;
+ }
+
+ memset(result.content, 0, length);
+ int read_result = fread(result.content, 1, length, file);
+ if (read_result == 0 && length != 0)
+ {
+ free(result.content);
+ result.content = 0;
+ return result;
+ }
+
+ result.content_length = read_result;
+
+ ((char*)result.content)[length] = 0;
+
+ fclose(file);
+ return result;
+}
+
+void ts_platform_list_files_block(ts_search_result* result, wchar_t* start_dir) {
+
+ utf8_int8_t* search_dir = (utf8_int8_t*)ts_memory_bucket_reserve(&result->memory, MAX_INPUT_LENGTH);
+ if (start_dir == nullptr) {
+ strcpy(search_dir, result->directory_to_search);
+ }
+ else {
+ strcpy(search_dir, (char*)start_dir);
+ }
+
+ // Append wildcard
+ utf8_int8_t* search_dir_fix = (utf8_int8_t*)ts_memory_bucket_reserve(&result->memory, MAX_INPUT_LENGTH);
+ strcpy(search_dir_fix, search_dir);
+ strcat(search_dir_fix, u8"/*");
+
+ DIR *d;
+ struct dirent *dir;
+ d = opendir(search_dir);
+ if (d) {
+ if (chdir(search_dir) != 0) return;
+ while ((dir = readdir(d)) != NULL) {
+ if (result->cancel_search) return;
+ if (chdir(search_dir) != 0) continue;
+
+ if (dir->d_type == DT_DIR)
+ {
+ if ((strcmp(dir->d_name, ".") == 0) || (strcmp(dir->d_name, "..") == 0))
+ continue;
+
+ utf8_int8_t complete_file_path[MAX_INPUT_LENGTH];
+ strcpy(complete_file_path, search_dir);
+ strcat(complete_file_path, "/");
+ strcat(complete_file_path, dir->d_name);
+
+ // do recursive search
+ ts_platform_list_files_block(result, (wchar_t*)complete_file_path);
+ }
+ // we handle DT_UNKNOWN for file systems that do not support type lookup.
+ else if (dir->d_type == DT_REG || dir->d_type == DT_UNKNOWN)
+ {
+ char *matched_filter = 0;
+ if (ts_filter_matches(&result->filters, dir->d_name, &matched_filter) == (size_t)-1) {
+ continue;
+ }
+ (void)matched_filter;
+
+
+ utf8_int8_t complete_file_path[MAX_INPUT_LENGTH];
+ strcpy(complete_file_path, search_dir);
+ strcat(complete_file_path, "/");
+ strcat(complete_file_path, dir->d_name);
+
+ ts_found_file* f = (ts_found_file*)ts_memory_bucket_reserve(&result->memory, sizeof(ts_found_file));
+ f->path = (utf8_int8_t*)ts_memory_bucket_reserve(&result->memory, MAX_INPUT_LENGTH);
+ f->match_count = 0;
+ f->error = 0;
+ f->collapsed = false;
+ strcpy(f->path, complete_file_path);
+
+ ts_mutex_lock(&result->files.mutex);
+ ts_array_push_size(&result->files, &f, sizeof(ts_found_file*));
+ ts_mutex_unlock(&result->files.mutex);
+ }
+ }
+ closedir(d);
+ }
+}
+
+uint64_t ts_platform_get_time(uint64_t compare) {
+ struct timespec tms;
+ if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&tms)) {
+ return -1;
+ }
+ uint64_t result = 0;
+ result = tms.tv_sec * 1000;
+ result += tms.tv_nsec / 1000000;
+
+ if (compare != 0) {
+ return (result - compare);
+ }
+
+ return result;
+}
+
+void ts_platform_open_file_as(utf8_int8_t* str) {
+ // not implemented
+}
+
+void ts_platform_open_file_in_folder(utf8_int8_t* file) {
+ // not implemented
+} \ No newline at end of file
diff --git a/src/unix/mutex.cpp b/src/unix/mutex.cpp
new file mode 100644
index 0000000..826ed33
--- /dev/null
+++ b/src/unix/mutex.cpp
@@ -0,0 +1,121 @@
+#include "mutex.h"
+
+ts_thread ts_thread_start(void *(*start_routine) (void *), void *arg)
+{
+ ts_thread result;
+ result.valid = false;
+
+ pthread_attr_t attr;
+ int attr_init_result = pthread_attr_init(&attr);
+ if (attr_init_result)
+ return result;
+
+ int start_thread_result = pthread_create(&result.thread, &attr, start_routine, arg);
+ if (start_thread_result)
+ {
+ pthread_attr_destroy(&attr);
+ return result;
+ }
+
+ result.valid = true;
+ pthread_attr_destroy(&attr);
+
+ return result;
+}
+
+void ts_thread_detach(ts_thread *ts_thread)
+{
+ if (ts_thread->valid)
+ {
+ pthread_detach(ts_thread->thread);
+ }
+}
+
+void ts_thread_join(ts_thread *ts_thread)
+{
+ if (ts_thread->valid)
+ {
+ void *retval;
+ pthread_join(ts_thread->thread, &retval);
+ }
+}
+
+bool ts_thread_tryjoin(ts_thread *ts_thread)
+{
+ if (ts_thread->valid)
+ {
+ void *retval;
+ bool thread_joined = !pthread_join(ts_thread->thread, &retval);
+ return thread_joined;
+ }
+ return false;
+}
+
+void ts_thread_exit()
+{
+ pthread_exit(0);
+}
+
+void ts_thread_stop(ts_thread *ts_thread)
+{
+ if (ts_thread->valid)
+ {
+ pthread_cancel(ts_thread->thread);
+ }
+}
+
+ts_mutex ts_mutex_create()
+{
+ ts_mutex result;
+
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
+
+ pthread_mutex_init(&result.mutex, &attr);
+
+ pthread_mutexattr_destroy(&attr);
+
+ return result;
+}
+
+ts_mutex ts_mutex_create_recursive()
+{
+ ts_mutex result;
+
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+
+ pthread_mutex_init(&result.mutex, &attr);
+
+ pthread_mutexattr_destroy(&attr);
+
+ return result;
+}
+
+void ts_mutex_lock(ts_mutex *ts_mutex)
+{
+ pthread_mutex_lock(&ts_mutex->mutex);
+}
+
+bool ts_mutex_trylock(ts_mutex *ts_mutex)
+{
+ return !pthread_mutex_trylock(&ts_mutex->mutex);
+}
+
+void ts_mutex_unlock(ts_mutex *ts_mutex)
+{
+ pthread_mutex_unlock(&ts_mutex->mutex);
+}
+
+void ts_mutex_destroy(ts_mutex *ts_mutex)
+{
+ ts_mutex_unlock(ts_mutex);
+ pthread_mutex_destroy(&ts_mutex->mutex);
+}
+
+void ts_thread_sleep(int microseconds)
+{
+ usleep(microseconds);
+} \ No newline at end of file