/* 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;
}