#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #ifdef _WIN32 #include #include #include #define PATH_SEPARATOR "\\" #else #ifdef __unix__ #include #endif #define PATH_SEPARATOR "/" #endif #include "utils.h" // Get current process memory usage in MB int get_process_memory_mb(void) { #ifdef _WIN32 // Windows implementation using PSAPI PROCESS_MEMORY_COUNTERS pmc; HANDLE process = GetCurrentProcess(); if (GetProcessMemoryInfo(process, &pmc, sizeof(pmc))) { return (int)(pmc.WorkingSetSize / (1024 * 1024)); // Convert bytes to MB } return 0; #elif defined(__unix__) && defined(__linux__) // Linux implementation using /proc/self/status FILE* f = fopen("/proc/self/status", "r"); if (!f) return 0; int memory_mb = 0; char line[256]; while (fgets(line, sizeof(line), f)) { if (sscanf(line, "VmRSS: %d", &memory_mb) == 1) { fclose(f); return memory_mb / 1024; // Convert KB to MB } } fclose(f); return 0; #elif defined(__APPLE__) // macOS implementation (basic fallback) return 0; // Would need mach/mach.h for proper implementation #else // Generic fallback for other systems return 0; #endif } // Get CPU model name void get_cpu_model(char* buffer, size_t size) { #ifdef __linux__ FILE* f = fopen("/proc/cpuinfo", "r"); if (f) { char line[256]; while (fgets(line, sizeof(line), f)) { if (strncmp(line, "model name", 10) == 0) { char* colon = strchr(line, ':'); if (colon) { colon++; // Skip leading whitespace while (*colon == ' ') colon++; // Remove trailing newline char* newline = strchr(colon, '\n'); if (newline) *newline = '\0'; snprintf(buffer, size, "CPU: %s", colon); fclose(f); return; } } } fclose(f); } snprintf(buffer, size, "CPU: Unknown"); #elif defined(_WIN32) HKEY hKey; if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { char cpu_name[128]; DWORD size_read = sizeof(cpu_name); if (RegQueryValueExA(hKey, "ProcessorNameString", NULL, NULL, (LPBYTE)cpu_name, &size_read) == ERROR_SUCCESS) { snprintf(buffer, size, "CPU: %s", cpu_name); } else { snprintf(buffer, size, "CPU: Unknown"); } RegCloseKey(hKey); } else { snprintf(buffer, size, "CPU: Unknown"); } #else snprintf(buffer, size, "CPU: Unknown"); #endif } // Get GPU model name void get_gpu_model(char* buffer, size_t size) { #ifdef __linux__ FILE* f = popen("glxinfo -B 2>/dev/null | grep -i 'OpenGL renderer' | head -1", "r"); if (f) { char line[256]; if (fgets(line, sizeof(line), f)) { // Extract GPU name after "OpenGL renderer string: " char* gpu_name = strstr(line, ":"); if (gpu_name) { gpu_name++; while (*gpu_name == ' ') gpu_name++; char* newline = strchr(gpu_name, '\n'); if (newline) *newline = '\0'; snprintf(buffer, size, "GPU: %s", gpu_name); pclose(f); return; } } pclose(f); } snprintf(buffer, size, "GPU: Unknown"); #elif defined(_WIN32) // Try multiple registry paths for better compatibility const char* paths[] = { "HARDWARE\\DEVICEMAP\\VIDEO\\Device0", "SYSTEM\\ControlSet001\\Services\\nvlddmkm\\Device0", NULL }; for (int i = 0; paths[i] != NULL; i++) { HKEY hKey; if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, paths[i], 0, KEY_READ, &hKey) == ERROR_SUCCESS) { char gpu_name[256]; DWORD size_read = sizeof(gpu_name); // Try different value names const char* values[] = {"Device Description", "DriverDesc", NULL}; for (int j = 0; values[j] != NULL; j++) { if (RegQueryValueExA(hKey, values[j], NULL, NULL, (LPBYTE)gpu_name, &size_read) == ERROR_SUCCESS) { snprintf(buffer, size, "GPU: %s", gpu_name); RegCloseKey(hKey); return; } } RegCloseKey(hKey); } } // Fallback: try the primary display device path HKEY hKey; if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { RegCloseKey(hKey); } snprintf(buffer, size, "GPU: Unknown"); #else snprintf(buffer, size, "GPU: Unknown"); #endif } // Get kernel info void get_kernel_info(char* buffer, size_t size) { #ifdef __linux__ FILE* f = popen("uname -r", "r"); if (f) { char kernel[128]; if (fgets(kernel, sizeof(kernel), f)) { char* newline = strchr(kernel, '\n'); if (newline) *newline = '\0'; snprintf(buffer, size, "Kernel: %s", kernel); pclose(f); return; } pclose(f); } snprintf(buffer, size, "Kernel: Unknown"); #elif defined(_WIN32) OSVERSIONINFOA osvi; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); if (GetVersionExA(&osvi)) { snprintf(buffer, size, "Kernel: Windows %lu.%lu", osvi.dwMajorVersion, osvi.dwMinorVersion); } else { snprintf(buffer, size, "Kernel: Unknown"); } #else snprintf(buffer, size, "Kernel: Unknown"); #endif } // Get the Nth-from-last line from chathistory file (1 = last line, 2 = second-to-last, etc.) // Returns false if there are fewer than N lines in the file bool get_chat_history_line(int lines_back, char* out_line, size_t max_len) { out_line[0] = '\0'; if (lines_back < 1) return false; FILE* file = fopen("./chathistory", "r"); if (!file) return false; // Read all lines into a dynamic array char** lines = NULL; int line_count = 0; int capacity = 0; char line[256]; while (fgets(line, sizeof(line), file) != NULL) { // Remove trailing newline size_t len = strlen(line); if (len > 0 && line[len - 1] == '\n'){line[len - 1] = '\0';} // Skip empty lines if (line[0] == '\0') continue; // Resize array if needed if (line_count >= capacity) { capacity = (capacity == 0) ? 10 : capacity * 2; char** new_lines = (char**)realloc(lines, capacity * sizeof(char*)); if (!new_lines) { // Error - free and return for (int i = 0; i < line_count; i++) free(lines[i]); free(lines); fclose(file); return false; } lines = new_lines; } // Add line lines[line_count] = (char*)malloc(strlen(line) + 1); if (!lines[line_count]) { for (int i = 0; i < line_count; i++) free(lines[i]); free(lines); fclose(file); return false; } strcpy(lines[line_count], line); line_count++; } fclose(file); // Get the Nth-from-last line if (lines_back > line_count) { // Not enough lines for (int i = 0; i < line_count; i++) free(lines[i]); free(lines); return false; } int index = line_count - lines_back; strncpy(out_line, lines[index], max_len - 1); out_line[max_len - 1] = '\0'; // Free memory for (int i = 0; i < line_count; i++) free(lines[i]); free(lines); return true; } // Trim whitespace from both ends of a string void trim_string(char* str) { if (!str || str[0] == '\0') return; // Trim trailing whitespace int len = strlen(str); while (len > 0 && (str[len - 1] == ' ' || str[len - 1] == '\t' || str[len - 1] == '\n' || str[len - 1] == '\r')) { str[--len] = '\0'; } // Trim leading whitespace int start = 0; while (str[start] && (str[start] == ' ' || str[start] == '\t')) { start++; } if (start > 0) { memmove(str, str + start, strlen(str + start) + 1); } }