summaryrefslogtreecommitdiff
path: root/menu.c
blob: b73c745b85c1ab28e6db28cded1fd70387be13ce (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include <ctype.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>

#include "menu.h"
#include "ui.h"
#include "util.h"

#define MAX_PASS	128
#define NO_OPT		0

static char pass[MAX_PASS];

static int getip(const State *state, int fd);
static pid_t run(const char *cmd);
static void updatestat(const State *state, unsigned typ, int pos);

int menuinit(const State *state, int fd)
{
	int rc, wfd = -1, status = 0;
	pid_t pid;

	if (state->floc)
		if ((wfd = open(state->floc, O_WRONLY | O_CREAT)) == -1)
			die ("can't open %s", state->floc);

	do {
		if (WEXITSTATUS(status))
			pui(state->headerr, state->statfail);
		else
			pui(state->cmds[PASS].name, state->statstr[0]);

		rc = getip(state, fd);

		if (wfd >= 0 && rc == PASS)
			write(wfd, pass, strlen(pass));

		pid = run(state->cmds[rc].cmd);
		if (rc == PASS) {
			pui(state->headverf, state->statverf);
			waitpid(pid, &status, NO_OPT);
		}
	} while (WEXITSTATUS(status) || rc != PASS);

	if (wfd >= 0)
		close(wfd);

	return rc;
}

static int getip(const State *state, int fd)
{
	unsigned i;
	int rc, floor, ceil;

	rc = floor = ceil = PASS;
	if (state->cmds[DOWN].name)
		floor = DOWN;
	if (state->cmds[UP].name)
		ceil = UP;

	for (i = 0; i + 1 < MAX_PASS; ) {
		read(fd, pass + i, 1);

		if (pass[i] == DEL) {
			if (i > 0)
				--i;
		} else if (pass[i] == NL) {
			break;
		} else if (i >= 2 && pass[i-2] == ESC && pass[i-1] == '[' ) {
			if (pass[i] == 'A' && rc < ceil)
				++rc;
			else if (pass[i] == 'B' && rc > floor)
				--rc;
			i -= 2;
      		} else {
			++i;
      		}

		pheader(state->cmds[rc].name);
		updatestat(state, rc, i);
	}

	pass[i] = '\0';
	return rc;
}

static void updatestat(const State *state, unsigned typ, int pos)
{
	if (typ == PASS) {
		if (pos)
			genrandstat(state->cmds[PASS].name, state->statstr);
		else
			pstaticstat(state->cmds[PASS].name, state->statstr[0]);
	} else {
		pstaticstat(state->cmds[typ].name, state->statverf);
	}
}

static pid_t run(const char *cmd)
{
	pid_t pid;

	if ((pid = fork()) == 0) {
		close(STDIN_FILENO);
		close(STDOUT_FILENO);
		close(STDERR_FILENO);
		execlp("sh", "sh", "-c", cmd, NULL);
		die("run: fork(): %s", cmd);
	}

	return pid;
}