textselect

Interactively select lines and pipe it to a command
Log | Files | Refs | README | LICENSE

commit b50429aadb6bd9b127f013d49029e31a378cbbe3
parent 0a5760e31225f49a0089579bfc4fc6783e64a688
Author: Friedel Schön <derfriedmundschoen@gmail.com>
Date:   Wed,  7 Aug 2024 00:29:29 +0200

structuring file like suckless

Diffstat:
Mtextselect.c | 234++++++++++++++++++++++++++++++++++++--------------------------------------------
1 file changed, 105 insertions(+), 129 deletions(-)

diff --git a/textselect.c b/textselect.c @@ -13,30 +13,33 @@ #define NORETURN __attribute__((noreturn)) + +void buffer_grow(void); +char* buffer_getline(size_t line); +void die(const char* message); +void drawscreen(void); +void execute(char** argv); +void handlescreen(void); +void help(void); +void loadfile(const char* filename); +void printselected(int fd); +void runcommand_pipe(char** argv); +void runcommand_xargs(int argc, char** argv); +void runcommand_xlines(int argc, char** argv); +void runcommand_xreplace(int argc, char** argv); +NORETURN void usage(int exitcode); + +char* argv0 = NULL; char* buffer = NULL; size_t buffer_size = 0; size_t buffer_alloc = 0; int buffer_lines = 0; -bool* selected = NULL; -bool selected_invert = false; -char* argv0 = NULL; int current_line = 0; int head_line = 0; int height = 0; +bool* selected = NULL; +bool selected_invert = false; -/** - * @brief Handles error messages and exits the program. - * - * @param message Error message to print. - */ -void die(const char* message) { - perror(message); - exit(EXIT_FAILURE); -} - -/** - * @brief Allocates memory for the buffer, growing it by BUFFERGROW bytes. - */ void buffer_grow(void) { char* newbuffer; if ((newbuffer = realloc(buffer, buffer_alloc += BUFFERGROW)) == NULL) { @@ -45,46 +48,6 @@ void buffer_grow(void) { buffer = newbuffer; } -/** - * @brief Loads a file into memory, storing its lines in the buffer. - * - * @param filename Name of the file to load, or NULL to read from stdin. - */ -void loadfile(const char* filename) { - static char readbuf[READBUFFER]; - ssize_t nread; - int fd; - - if ((fd = open(filename, O_RDONLY)) == -1) die("Failed to open file"); - - while ((nread = read(fd, readbuf, sizeof(readbuf))) > 0) { - for (ssize_t i = 0; i < nread; i++) { - if (buffer_size == buffer_alloc) buffer_grow(); - - if (readbuf[i] == '\n') { - if (buffer[buffer_size - 1] != '\0') { - buffer[buffer_size++] = '\0'; - buffer_lines++; - } - } else { - buffer[buffer_size++] = readbuf[i]; - } - } - } - - buffer[buffer_size++] = '\0'; - if (fd > 2) close(fd); - - selected = calloc(buffer_lines, sizeof(bool)); - if (selected == NULL) die("allocating chosen_lines"); -} - -/** - * @brief Retrieves a line from the buffer. - * - * @param line Line number to retrieve. - * @return Pointer to the start of the line. - */ char* buffer_getline(size_t line) { size_t current = 0; if (line == 0) return buffer; @@ -97,9 +60,11 @@ char* buffer_getline(size_t line) { return NULL; } -/** - * @brief Prints lines to the ncurses window. - */ +void die(const char* message) { + perror(message); + exit(EXIT_FAILURE); +} + void drawscreen(void) { werase(stdscr); for (int i = 0; i < height && (head_line + i) < buffer_lines; i++) { @@ -111,62 +76,19 @@ void drawscreen(void) { wrefresh(stdscr); } -/** - * @brief Prints the chosen lines to the specified file descriptor. - * - * @param fd File descriptor to print to. - */ -void printselected(int fd) { - size_t current = 0; - if (selected[0] != selected_invert) - dprintf(fd, "%s\n", buffer); - - for (size_t i = 0; i < buffer_size; i++) { - if (buffer[i] == '\0') { - current++; - if (selected[current] != selected_invert) - dprintf(fd, "%s\n", &buffer[i + 1]); - } - } -} +void execute(char** argv) { + pid_t pid; -/** - * @brief Displays usage information and exits the program. - * - * @param exitcode Exit code. - */ -NORETURN void usage(int exitcode) { - fprintf(stderr, "Usage: %s [-hvx] [-o output] <input> [command ...]\n", argv0); - exit(exitcode); -} + if ((pid = fork()) == -1) + die("fork"); -void help(void) { - fprintf(stderr, - "Usage: %s [-hvx] [-o output] <input> [command [args...]]\n" - "Interactively select lines from a text file and optionally execute a command with the selected lines.\n" - "\n" - "Options:\n" - " -h Display this help message and exit\n" - " -v Invert the selection of lines\n" - " -x Call command with selected lines as arguement\n" - " -o output Specify an output file to save the selected lines\n" - "\n" - "Navigation and selection keys:\n" - " UP, LEFT Move the cursor up\n" - " DOWN, RIGHT Move the cursor down\n" - " v Invert the selection of lines\n" - " SPACE Select or deselect the current line\n" - " ENTER, q Quit the selection interface\n" - "\n" - "Examples:\n" - " textselect -o output.txt input.txt\n" - " textselect input.txt sort\n", - argv0); + if (pid == 0) { + execvp(*argv, argv); + die("execvp"); + } + wait(NULL); } -/** - * @brief Initializes and handles the ncurses window for line selection. - */ void handlescreen(void) { bool quit = false; @@ -213,11 +135,73 @@ void handlescreen(void) { endwin(); } -/** - * @brief Executes a command and passes the chosen lines as stdin. - * - * @param argv Command and its arguments. - */ +void help(void) { + fprintf(stderr, + "Usage: %s [-hvx] [-o output] <input> [command [args...]]\n" + "Interactively select lines from a text file and optionally execute a command with the selected lines.\n" + "\n" + "Options:\n" + " -h Display this help message and exit\n" + " -v Invert the selection of lines\n" + " -x Call command with selected lines as argument\n" + " -o output Specify an output file to save the selected lines\n" + "\n" + "Navigation and selection keys:\n" + " UP, LEFT Move the cursor up\n" + " DOWN, RIGHT Move the cursor down\n" + " v Invert the selection of lines\n" + " SPACE Select or deselect the current line\n" + " ENTER, q Quit the selection interface\n" + "\n" + "Examples:\n" + " textselect -o output.txt input.txt\n" + " textselect input.txt sort\n", + argv0); +} + +void loadfile(const char* filename) { + static char readbuf[READBUFFER]; + ssize_t nread; + int fd; + + if ((fd = open(filename, O_RDONLY)) == -1) die("Failed to open file"); + + while ((nread = read(fd, readbuf, sizeof(readbuf))) > 0) { + for (ssize_t i = 0; i < nread; i++) { + if (buffer_size == buffer_alloc) buffer_grow(); + + if (readbuf[i] == '\n') { + if (buffer[buffer_size - 1] != '\0') { + buffer[buffer_size++] = '\0'; + buffer_lines++; + } + } else { + buffer[buffer_size++] = readbuf[i]; + } + } + } + + buffer[buffer_size++] = '\0'; + if (fd > 2) close(fd); + + selected = calloc(buffer_lines, sizeof(bool)); + if (selected == NULL) die("allocating selected"); +} + +void printselected(int fd) { + size_t current = 0; + if (selected[0] != selected_invert) + dprintf(fd, "%s\n", buffer); + + for (size_t i = 0; i < buffer_size; i++) { + if (buffer[i] == '\0') { + current++; + if (selected[current] != selected_invert) + dprintf(fd, "%s\n", &buffer[i + 1]); + } + } +} + void runcommand_pipe(char** argv) { int pipefd[2]; pid_t pid; @@ -239,19 +223,6 @@ void runcommand_pipe(char** argv) { } } -void execute(char** argv) { - pid_t pid; - - if ((pid = fork()) == -1) - die("fork"); - - if (pid == 0) { - execvp(*argv, argv); - die("execvp"); - } - wait(NULL); -} - void runcommand_xargs(int argc, char** argv) { char** newargv; int chosencount = argc + 1; // + NULL @@ -329,6 +300,11 @@ void runcommand_xreplace(int argc, char** argv) { } } +NORETURN void usage(int exitcode) { + fprintf(stderr, "Usage: %s [-hvx] [-o output] <input> [command ...]\n", argv0); + exit(exitcode); +} + int main(int argc, char* argv[]) { char* output = NULL; bool xargs = false;