// #include #ifdef _WIN32 #include #include #include #include #include #include #else #include #include #include #include #include #include #include #include #include #include #include #include #endif // Special key codes (unified across platforms) #define KEY_ARROW_UP 1001 #define KEY_ARROW_DOWN 1002 #define KEY_ARROW_RIGHT 1003 #define KEY_ARROW_LEFT 1004 int terminkey(); void echooff(); void echoon(); int termwidth(); int ipc_init(); int ipc_check_message(uintptr_t buffer_ptr, int max_len); void ipc_send_message(const char* message); void ipc_cleanup(); void get_absolute_path(const char* rel_path, uintptr_t abs_path_ptr, int max_len); #ifdef _WIN32 static HANDLE hServerPipe = INVALID_HANDLE_VALUE; int terminkey() { if (_kbhit()) { int ch = _getch(); // Handle Windows arrow keys if (ch == 224) { int next = _getch(); switch (next) { case 72: return KEY_ARROW_UP; case 80: return KEY_ARROW_DOWN; case 75: return KEY_ARROW_LEFT; case 77: return KEY_ARROW_RIGHT; default: return next; } } return ch; } return -1; } void echooff() { HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); DWORD mode = 0; GetConsoleMode(hStdin, &mode); SetConsoleMode(hStdin, mode & ~ENABLE_ECHO_INPUT); } void echoon() { HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); DWORD mode = 0; GetConsoleMode(hStdin, &mode); SetConsoleMode(hStdin, mode | ENABLE_ECHO_INPUT); } int termwidth() { HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO csbi; if (GetConsoleScreenBufferInfo(hStdout, &csbi)) { return csbi.srWindow.Right - csbi.srWindow.Left + 1; } return -1; } int ipc_init() { hServerPipe = CreateNamedPipe( "\\\\.\\pipe\\cimp_ipc", PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 1, 4096, 4096, 0, NULL ); if (hServerPipe == INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); if (err == ERROR_ACCESS_DENIED || err == ERROR_PIPE_BUSY) { return 0; // Already running } return -1; // Other error } ConnectNamedPipe(hServerPipe, NULL); return 1; } int ipc_check_message(uintptr_t buffer_ptr, int max_len) { if (hServerPipe == INVALID_HANDLE_VALUE) return 0; char* buffer = (char*)buffer_ptr; DWORD bytesRead = 0; // Check if a client is connected (or already connected) BOOL connected = ConnectNamedPipe(hServerPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); if (connected) { DWORD bytesAvail = 0; // Sneak peek to see if data has safely arrived in the buffer yet if (PeekNamedPipe(hServerPipe, NULL, 0, NULL, &bytesAvail, NULL)) { if (bytesAvail > 0) { // Data is ready, perform the read safely BOOL success = ReadFile(hServerPipe, buffer, max_len - 1, &bytesRead, NULL); if (success && bytesRead > 0) { buffer[bytesRead] = '\0'; DisconnectNamedPipe(hServerPipe); ConnectNamedPipe(hServerPipe, NULL); // Re-arm for next connection return (int)bytesRead; } } } else { // If Peek fails because the client dropped out without sending anything if (GetLastError() == ERROR_BROKEN_PIPE) { DisconnectNamedPipe(hServerPipe); ConnectNamedPipe(hServerPipe, NULL); } } } return 0; } void ipc_send_message(const char* message) { HANDLE hPipe = CreateFile( "\\\\.\\pipe\\cimp_ipc", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); if (hPipe != INVALID_HANDLE_VALUE) { DWORD bytesWritten = 0; WriteFile(hPipe, message, strlen(message), &bytesWritten, NULL); CloseHandle(hPipe); } } void ipc_cleanup() { if (hServerPipe != INVALID_HANDLE_VALUE) { CloseHandle(hServerPipe); hServerPipe = INVALID_HANDLE_VALUE; } } void get_absolute_path(const char* rel_path, uintptr_t abs_path_ptr, int max_len) { char* abs_path = (char*)abs_path_ptr; _fullpath(abs_path, rel_path, max_len); } #else static int server_fd = -1; static char socket_path[256] = ""; static void get_socket_path() { if (socket_path[0] == '\0') { uid_t uid = getuid(); snprintf(socket_path, sizeof(socket_path), "/tmp/cimp_ipc_%u.sock", (unsigned int)uid); } } int terminkey() { struct termios oldt, newt; int ch; int oldf; // Save existing terminal settings tcgetattr(STDIN_FILENO, &oldt); newt = oldt; // Disable buffering and echoing newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); // Set STDIN to non-blocking oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); ch = getchar(); // Handle Unix arrow keys (ESC [ A/B/C/D) if (ch == 27) { int next1 = getchar(); if (next1 == '[') { int next2 = getchar(); switch (next2) { case 'A': ch = KEY_ARROW_UP; break; case 'B': ch = KEY_ARROW_DOWN; break; case 'C': ch = KEY_ARROW_RIGHT; break; case 'D': ch = KEY_ARROW_LEFT; break; } } } // Restore terminal settings tcsetattr(STDIN_FILENO, TCSANOW, &oldt); fcntl(STDIN_FILENO, F_SETFL, oldf); return ch; } void echooff() { struct termios tty; tcgetattr(STDIN_FILENO, &tty); tty.c_lflag &= ~ECHO; tcsetattr(STDIN_FILENO, TCSANOW, &tty); } void echoon() { struct termios tty; tcgetattr(STDIN_FILENO, &tty); tty.c_lflag |= ECHO; tcsetattr(STDIN_FILENO, TCSANOW, &tty); } int termwidth() { struct winsize w; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) { return w.ws_col; } return -1; } int ipc_init() { get_socket_path(); int test_fd = socket(AF_UNIX, SOCK_STREAM, 0); if (test_fd >= 0) { struct sockaddr_un addr; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1); if (connect(test_fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) { close(test_fd); return 0; // Already running } close(test_fd); } unlink(socket_path); server_fd = socket(AF_UNIX, SOCK_STREAM, 0); if (server_fd < 0) { return -1; } int flags = fcntl(server_fd, F_GETFL, 0); fcntl(server_fd, F_SETFL, flags | O_NONBLOCK); struct sockaddr_un addr; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1); if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { close(server_fd); server_fd = -1; return -1; } if (listen(server_fd, 5) < 0) { close(server_fd); server_fd = -1; unlink(socket_path); return -1; } return 1; } int ipc_check_message(uintptr_t buffer_ptr, int max_len) { if (server_fd < 0) return 0; char* buffer = (char*)buffer_ptr; int client_fd = accept(server_fd, NULL, NULL); if (client_fd < 0) { return 0; } int total_read = 0; while (total_read < max_len - 1) { int r = read(client_fd, buffer + total_read, max_len - 1 - total_read); if (r <= 0) break; total_read += r; } buffer[total_read] = '\0'; close(client_fd); return total_read; } void ipc_send_message(const char* message) { get_socket_path(); int client_fd = socket(AF_UNIX, SOCK_STREAM, 0); if (client_fd < 0) return; struct sockaddr_un addr; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1); if (connect(client_fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) { int total_written = 0; int len = strlen(message); while (total_written < len) { int w = write(client_fd, message + total_written, len - total_written); if (w <= 0) break; total_written += w; } } close(client_fd); } void ipc_cleanup() { if (server_fd >= 0) { close(server_fd); server_fd = -1; } get_socket_path(); unlink(socket_path); } void get_absolute_path(const char* rel_path, uintptr_t abs_path_ptr, int max_len) { char* abs_path = (char*)abs_path_ptr; char resolved[PATH_MAX]; if (realpath(rel_path, resolved) != NULL) { strncpy(abs_path, resolved, max_len); abs_path[max_len - 1] = '\0'; } else { if (rel_path[0] == '/') { strncpy(abs_path, rel_path, max_len); abs_path[max_len - 1] = '\0'; } else { char cwd[PATH_MAX]; if (getcwd(cwd, sizeof(cwd)) != NULL) { snprintf(abs_path, max_len, "%s/%s", cwd, rel_path); } else { strncpy(abs_path, rel_path, max_len); abs_path[max_len - 1] = '\0'; } } } } #endif