summaryrefslogtreecommitdiff
path: root/renu.c
diff options
context:
space:
mode:
authorKrow Savcik <krow@savcik.xyz>2025-08-31 15:11:01 +0200
committerKrow Savcik <krow@savcik.xyz>2025-08-31 15:11:01 +0200
commit0fa7537ce5006a9c99bc7e295a4ae4ff0b920fda (patch)
tree057a91b30ab61417970c5defe825ce16a094ac39 /renu.c
initial commitHEADmaster
Diffstat (limited to 'renu.c')
-rw-r--r--renu.c387
1 files changed, 387 insertions, 0 deletions
diff --git a/renu.c b/renu.c
new file mode 100644
index 0000000..742d0c2
--- /dev/null
+++ b/renu.c
@@ -0,0 +1,387 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "util.h"
+#include "debug.h"
+#include "config.h"
+
+#define MAXLINE 128
+
+static char menu[MAXLINE];
+
+void
+usage()
+{
+ printf("remu [FILE]\n");
+ exit(0);
+}
+
+int
+launch_menu(int *pfd, char *prompt)
+{
+ int pipefd[4];
+ pid_t pid;
+ if (pipe(pipefd))
+ return 1;
+ if (pipe(&pipefd[2])) {
+ close(pipefd[0]);
+ close(pipefd[1]);
+ return 1;
+ }
+
+ pid = fork();
+
+ switch (pid) {
+ case -1:
+ close(pipefd[0]);
+ close(pipefd[1]);
+ close(pipefd[2]);
+ close(pipefd[3]);
+ return 1;
+ case 0:
+ break;
+ default:
+ pfd[0] = pipefd[0];
+ pfd[1] = pipefd[3];
+ close(pipefd[1]);
+ close(pipefd[2]);
+ return 0;
+ }
+
+ /* Child process */
+ close(pipefd[0]);
+ close(pipefd[3]);
+
+ if (dup2(pipefd[1], STDOUT_FILENO) == -1)
+ exit(1);
+ if (dup2(pipefd[2], STDIN_FILENO) == -1)
+ exit(1);
+
+ execvp(menu_cmd[0], (char **)menu_cmd);
+ close(pipefd[1]);
+ close(pipefd[2]);
+ exit(0);
+}
+
+char *
+nextline(char *c)
+{
+ while (*c != '\n')
+ c++;
+
+ return ++c;
+}
+
+char *
+setline(char *p)
+{
+ char *end;
+ end = nextline(p);
+ end[-1] = 0;
+ return end;
+}
+
+void
+resetline(char *end)
+{
+ end[-1] = '\n';
+}
+
+char *
+nextarg(char *c)
+{
+ while (*c == '\0')
+ c++;
+
+ return c;
+}
+
+char *
+process_quoted(char *pnt)
+{
+ size_t off = 0;
+ char *ret = NULL;
+ pnt[0] = 0;
+ pnt++;
+ while (pnt[off] != '"') {
+ if (pnt[off] == '\0' || pnt[off] == '\n')
+ return NULL;
+
+ if (pnt[off] == '\\') {
+ if (pnt[off+1] == '\0' || pnt[off+1] == '\n')
+ return NULL;
+ off++;
+ }
+ pnt[0] = pnt[off];
+ pnt++;
+ }
+
+ for (ret = &(pnt[off+1]); pnt != ret; pnt++)
+ pnt[0] = 0;
+
+ return ret;
+}
+
+char *
+process_unquoted(char *pnt)
+{
+ size_t off = 0;
+ char *ret = NULL;
+ while (pnt[off] && pnt[off] != '\n') {
+ if (pnt[off] == ' ') {
+ ret = &pnt[off+1];
+ break;
+ }
+
+ if (pnt[off] == '"')
+ return NULL;
+
+ if (pnt[off] == '\\') {
+ if (pnt[off+1] == '\0' || pnt[off+1] == '\n')
+ return NULL;
+ off++;
+ }
+ pnt[0] = pnt[off];
+ pnt++;
+ }
+
+ ret = ret ? ret : &pnt[off];
+
+ for (; pnt != ret; pnt++)
+ pnt[0] = 0;
+
+ return ret;
+}
+
+char *
+process_line(char *pnt)
+{
+ while (*pnt && *pnt != '\n') {
+ if (*pnt == '"')
+ pnt = process_quoted(pnt);
+ else
+ pnt = process_unquoted(pnt);
+
+ if (pnt == NULL)
+ return NULL;
+ }
+
+ return pnt;
+}
+
+unsigned int
+preprocess(char *buf)
+{
+ char *pnt = buf;
+ unsigned int line = 0;
+ while (*pnt) {
+ line++;
+ if (*pnt == '#' || *pnt == '\n') {
+ pnt = nextline(pnt);
+ continue;
+ }
+
+ if (pnt[1] != ' ')
+ return line;
+
+ pnt[1] = 0;
+ pnt = process_line(pnt+2);
+ if (pnt == NULL)
+ return line;
+ pnt = nextline(pnt);
+ }
+
+ return 0;
+}
+
+int
+submenu(char *line)
+{
+ char *e, *arg, *ea;
+ arg = nextarg(line+2);
+ ea = &arg[strlen(arg) - 1];
+ if (*ea == '\n')
+ return 1;
+
+ arg = nextarg(ea+1);
+ e = setline(line);
+ strncpy(menu, arg, MAXLINE);
+ menu[MAXLINE-1] = 0;
+ resetline(e);
+ return 0;
+}
+
+int
+print(char *line)
+{
+ char *e, *arg, *ea;
+ arg = nextarg(line+2);
+
+ ea = &arg[strlen(arg) - 1];
+ if (*ea != '\n' && *nextarg(ea+1) != '\n')
+ arg = nextarg(ea+1);
+
+ e = setline(line);
+ printf("%s\n", arg);
+ resetline(e);
+ return 0;
+}
+
+int
+run(char *line)
+{
+ char *e, *arg, *ea;
+ arg = nextarg(line+2);
+
+ ea = &arg[strlen(arg) - 1];
+ if (*ea == '\n')
+ return 1;
+
+ arg = nextarg(ea+1);
+ e = setline(line);
+ if (execl("/bin/sh", "sh", "-c", arg, NULL))
+ error("Error executing process: %s\n", strerror(errno));
+ resetline(e);
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *buf, *stop, *pnt, *end, *mpnt, *line;
+ unsigned int i;
+ int pfd[2];
+ FILE *f[2];
+ char option[MAXLINE];
+
+ strcpy(menu, default_menu);
+
+ if (argc != 2)
+ usage();
+
+ buf = f_read(argv[1]);
+ if (buf == NULL) {
+ fprintf(stderr, "Couldn't read file %s\n", argv[1]);
+ return 1;
+ }
+
+ stop = &buf[strlen(buf)];
+ if (stop == buf) {
+ fprintf(stderr, "Wrong format in %s: Empty file\n", argv[1]);
+ return 1;
+ } else if (stop[-1] != '\n') {
+ fprintf(stderr, "Wrong format in %s: Missing EOL at the end of the file\n", argv[1]);
+ return 1;
+ }
+
+ if (i = preprocess(buf)) {
+ fprintf(stderr, "Wrong format in %s:%u\n", argv[1], i);
+ return 1;
+ }
+
+
+ while (1) {
+ for (pnt = buf; pnt != stop; pnt = nextline(pnt)) {
+ if (*pnt != 'm')
+ continue;
+ pnt = nextarg(pnt+1);
+ end = setline(pnt);
+
+ if (strcmp(menu, pnt) == 0)
+ break;
+ resetline(end);
+ }
+
+ if (pnt == stop) {
+ fprintf(stderr, "Couldn't find menu %s in file %s\n", menu, argv[1]);
+ return 1;
+ }
+
+ resetline(end);
+
+ /* Query option */
+ if (launch_menu(pfd, NULL)) {
+ fprintf(stderr, "Couldn't open the menu\n");
+ return 1;
+ }
+
+ f[0] = fdopen(pfd[0], "r");
+ f[1] = fdopen(pfd[1], "w");
+
+ if (f[0] == NULL || f[1] == NULL) {
+ fprintf(stderr, "Couldn't open the menu\n");
+ return 1;
+ }
+
+ mpnt = nextline(pnt);
+ for (pnt = mpnt; pnt != stop; pnt = nextline(pnt)) {
+ if (*pnt == 'm')
+ break;
+
+ if (*pnt == '\n' || *pnt == '#')
+ continue;
+
+ pnt = nextarg(pnt+1);
+ end = setline(pnt);
+ fprintf(f[1], "%s\n", pnt);
+ resetline(end);
+ }
+
+ fclose(f[1]);
+ close(pfd[1]);
+
+ if (fgets(option, MAXLINE, f[0]) == NULL) {
+ fprintf(stderr, "Couldn't open the menu\n");
+ return 1;
+ }
+ option[strlen(option)-1] = 0;
+
+ for (line = mpnt; line != stop; line = nextline(line)) {
+ if (*line == 'm')
+ break;
+
+ if (*line == '\n' || *line == '#')
+ continue;
+
+ pnt = nextarg(line+1);
+
+ if (*pnt == '\n') {
+ fprintf(stderr, "Wrong format in %s: Not enough arguments\n", argv[1]);
+ return 1;
+ }
+
+ end = setline(pnt);
+ if (strcmp(pnt, option) == 0)
+ break;
+ resetline(end);
+ }
+
+ /* No option selected */
+ if (*line == 'm' || line == stop)
+ break;
+
+ resetline(end);
+ switch (line[0]) {
+ case 's':
+ if (submenu(line)) {
+ fprintf(stderr, "Wrong format in %s: Not enough arguments\n", argv[1]);
+ return 1;
+ }
+ break;
+ case 'p':
+ print(line);
+ return 0;
+ case 'r':
+ if (run(line)) {
+ fprintf(stderr, "Wrong format in %s: Not enough arguments\n", argv[1]);
+ return 1;
+ }
+ return 0;
+ default:
+ return 0;
+ }
+ }
+}