changeset 0:21b543c7aa14

Initial commit
author Yasuri <yasuri@charliesmp.net>
date Sun, 13 Sep 2026 19:19:56 +0000
parents
children a17d9d25e9ea
files .hgignore Makefile main.cpp pipes.cpp process.h spawn.cpp
diffstat 6 files changed, 148 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Sun Sep 13 19:19:56 2026 +0000
@@ -0,0 +1,11 @@
+syntax: glob
+
+*.o
+xt
+xbpst
+*.out
+*.exe
+.vscode/
+.idea/
+*.swp
+*~
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Sun Sep 13 19:19:56 2026 +0000
@@ -0,0 +1,18 @@
+CXX := g++
+CXXFLAGS := -std=c++17 -Wall -Wextra
+TARGET := xt
+SRCS := main.cpp spawn.cpp pipes.cpp
+OBJS := $(SRCS:.cpp=.o)
+
+.PHONY: all clean
+
+all: $(TARGET)
+
+$(TARGET): $(OBJS)
+	$(CXX) $(CXXFLAGS) $(OBJS) -o $(TARGET)
+
+%.o: %.cpp process.h
+	$(CXX) $(CXXFLAGS) -c $< -o $@
+
+clean:
+	rm -f $(OBJS) $(TARGET)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun Sep 13 19:19:56 2026 +0000
@@ -0,0 +1,31 @@
+#include <iostream>
+#include <sstream>
+#include "process.h"
+std::string extract_pkgname(const std::string& fzf_line) {
+    std::istringstream iss(fzf_line);
+    std::string marker, pkgver;
+    iss >> marker >> pkgver;
+    return pkgver;
+}
+int main() {
+    char* const query_argv[] = { const_cast<char*>("xbps-query"), const_cast<char*>("-Rs"), const_cast<char*>(""), nullptr };
+    std::string package_list = run_piped("/usr/bin/xbps-query", query_argv, ""); 
+    char* const fzf_argv[] = { const_cast<char*>("fzf"), nullptr };
+    std::string result = run_piped("/usr/bin/fzf", fzf_argv, package_list);
+
+    // strip trailing newline fzf adds
+    if (!result.empty() && result.back() == '\n') {
+        result.pop_back();
+    }
+    std::string pkgname = extract_pkgname(result);
+    char* const install_argv[] = {
+        const_cast<char*>("doas"),
+        const_cast<char*>("xbps-install"),
+        const_cast<char*>("-Sy"),
+        pkgname.data(),
+        nullptr
+    };
+    std::string status = spawn(install_argv, "/usr/bin/doas");
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pipes.cpp	Sun Sep 13 19:19:56 2026 +0000
@@ -0,0 +1,55 @@
+#include <iostream>
+#include <unistd.h>
+#include <spawn.h>
+#include <cstring>
+#include <string>
+#include <sys/wait.h>
+#include "process.h"
+extern char** environ;
+std::string run_piped(const char* path, char* const argv[], const std::string& input) 
+{
+    int status;
+    pid_t pid;
+    int pipeA[2];
+    int pipeB[2];
+    if (pipe(pipeA) < 0)
+        return "error";
+    if (pipe(pipeB) < 0)
+        return "error";
+    posix_spawn_file_actions_t actions;
+    posix_spawn_file_actions_init(&actions); // initialize actions
+    posix_spawn_file_actions_adddup2(&actions, pipeA[0], STDIN_FILENO);
+    posix_spawn_file_actions_adddup2(&actions, pipeB[1], STDOUT_FILENO);
+    posix_spawn_file_actions_addclose(&actions, pipeA[1]); // closes write end in child
+    posix_spawn_file_actions_addclose(&actions, pipeB[0]); // makes sure child doesn't read its own output pipe
+    posix_spawn_file_actions_addclose(&actions, pipeA[0]); // close read fd in child
+    posix_spawn_file_actions_addclose(&actions, pipeB[1]); // close read fd in child, part 2
+    status = posix_spawn(&pid, path, &actions, NULL, const_cast<char* const*>(argv), environ);
+    close(pipeA[0]);
+    close(pipeB[1]);
+    if (status != 0) {
+        posix_spawn_file_actions_destroy(&actions);
+        close(pipeA[1]);
+        close(pipeB[0]);
+        std::cerr << "posix_spawn failed: " << strerror(status) << std::endl;
+        return "error";
+    }
+    write(pipeA[1],input.c_str(), input.size());
+    close(pipeA[1]);
+    char buf[256];
+std::string result;
+ssize_t n;
+while ((n = read(pipeB[0], buf, sizeof(buf))) > 0) {
+    result.append(buf, n);
+}
+    close(pipeB[0]);
+    if (waitpid(pid, &status, 0) == -1) {
+        posix_spawn_file_actions_destroy(&actions);
+        close(pipeA[1]);
+        close(pipeB[0]);
+        perror("waitpid");
+        return "error";
+    }
+    posix_spawn_file_actions_destroy(&actions);
+    return result; 
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/process.h	Sun Sep 13 19:19:56 2026 +0000
@@ -0,0 +1,4 @@
+#pragma once 
+#include <string>
+std::string spawn(char* const argv[], const char* path);
+std::string run_piped(const char* path, char* const argv[], const std::string& input);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spawn.cpp	Sun Sep 13 19:19:56 2026 +0000
@@ -0,0 +1,29 @@
+#include <iostream>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <spawn.h>
+#include <cstring>
+#include <string>
+#include "process.h"
+extern char** environ; // idk what this does
+std::string spawn(char* const argv[], const char* path)
+{
+    pid_t pid;
+    int status;
+    status = posix_spawn(&pid, path, NULL, NULL, const_cast<char* const*>(argv), environ);
+    if (status != 0) {
+        std::cerr << "posix_spawn failed:" << strerror(status) << std::endl;
+        return "error";
+    }
+    if (waitpid(pid, &status, 0) == -1) {
+        perror("waitpid");
+        return "error";
+    }
+    if (WIFEXITED(status)) {
+        return std::to_string(WEXITSTATUS(status));
+    }
+    if (WIFSIGNALED(status)) {
+        return std::to_string(WTERMSIG(status));
+    }
+    return "success";
+}