summaryrefslogblamecommitdiff
path: root/menu.c
blob: b73c745b85c1ab28e6db28cded1fd70387be13ce (plain) (tree)




















































































































                                                                               
#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;
}