/* This file is a part of rvsh * * Copyright (C) 2021 Robby Zambito * Copyright (C) 2022 Spencer Hall * * rvsh is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * rvsh is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include #include #include union pipe { int filedes[2]; struct { int read_end; int write_end; }; }; char *strrev(char *input) { size_t len, i; char a, z; len = strlen(input); while (isspace(input[len - 1])) { len--; } for (i = 0; i < len / 2; i++) { a = input[i]; z = input[len - i - 1]; input[i] = z; input[len - i - 1] = a; } return input; } char *get_bash_prompt() { pid_t bash_pid; union pipe bash_input, bash_output; FILE *bash_output_f; ssize_t len; int status; static char *prompt = NULL; static size_t prompt_capacity = 0; pipe(bash_input.filedes); pipe(bash_output.filedes); bash_pid = fork(); if (bash_pid == -1) { exit(EXIT_FAILURE); } if (bash_pid == 0) { close(bash_input.write_end); close(bash_output.read_end); dup2(bash_input.read_end, STDIN_FILENO); dup2(bash_output.write_end, STDOUT_FILENO); close(STDERR_FILENO); execlp("bash", "bash", "-i", "-c", "echo \"${PS1@P}\"", NULL); } close(bash_input.read_end); close(bash_output.write_end); bash_output_f = fdopen(bash_output.read_end, "r"); len = getline(&prompt, &prompt_capacity, bash_output_f); if (prompt[len - 1] == '\n') { prompt[len - 1] = '\0'; } fclose(bash_output_f); do { waitpid(bash_pid, &status, WUNTRACED); } while(!WIFEXITED(status) && !WIFSIGNALED(status)); return prompt; } void put_stream_rev(FILE *stream) { pid_t pid; char *line; size_t line_capacity; pid = fork(); if (pid == -1) { exit(EXIT_FAILURE); } if (pid == 0) { line = NULL; line_capacity = 0; while (getline(&line, &line_capacity, stream) > 0) { strrev(line); printf("%s", line); } free(line); } } void run_reverse_command(char *command) { pid_t bash_pid; union pipe bash_input, bash_output; FILE *bash_input_f, *bash_output_f; char *line; size_t line_capacity; int status; pipe(bash_input.filedes); pipe(bash_output.filedes); bash_pid = fork(); if (bash_pid == -1) { exit(EXIT_FAILURE); } if (bash_pid == 0) { close(bash_input.write_end); close(bash_output.read_end); dup2(bash_input.read_end, STDIN_FILENO); dup2(bash_output.write_end, STDOUT_FILENO); /*close(STDERR_FILENO);*/ execlp("bash", "bash", "-c", command, NULL); } close(bash_input.read_end); close(bash_output.write_end); bash_input_f = fdopen(bash_input.write_end, "w"); bash_output_f = fdopen(bash_output.read_end, "r"); line = NULL; line_capacity = 0; while (getline(&line, &line_capacity, bash_output_f) > 0) { strrev(line); printf("%s", line); } free(line); do { waitpid(bash_pid, &status, WUNTRACED); } while(!WIFEXITED(status) && !WIFSIGNALED(status)); fclose(bash_input_f); fclose(bash_output_f); } int main(void) { char *prompt; char *line; using_history(); while ((line = readline(strrev(prompt = get_bash_prompt()))) != NULL) { add_history(line); strrev(line); run_reverse_command(line); free(line); } if (errno != 0) { perror("End"); } rl_clear_history(); free(prompt); return EXIT_SUCCESS; }