#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <curses.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include "preferences.h"
#include "userinput.h"
#include "userinput_mode.h"
#include "userinput_sleep.h"
#include "userinput_order.h"
#include "userinput_secondary_order.h"
#include "userinput_user.h"
#include "userinput_signal.h"
#include "userinput_help.h"
#include "top.h"
static struct user_input_state *current_state = NULL;
static void reset_state(struct user_input_state *s) {
s->buf[0] = '\0';
s->offset = 0;
}
static void completion(void *tinst, struct user_input_state *s) {
reset_state(s);
current_state = NULL;
}
static void error_draw(void *tinst, struct user_input_state *s, WINDOW *win,
int row, int column) {
char display[60];
if(s->misc > 1) {
s->completion(tinst, s);
return;
}
if(-1 == snprintf(display, sizeof(display), "error: %s", s->buf))
return;
mvwaddstr(win, row, column, display);
s->misc++;
}
static struct user_input_state error_state = {
.offset = 0,
.completion = completion,
.draw = error_draw
};
void user_input_set_error_state(const char *err) {
current_state = &error_state;
reset_state(current_state);
current_state->misc = 0;
strncpy(current_state->buf, err, sizeof(current_state->buf));
current_state->buf[sizeof(current_state->buf) - 1] = '\0';
}
static void status_draw(void *tinst, struct user_input_state *s, WINDOW *win,
int row, int column) {
if(s->misc > 1) {
s->completion(tinst, s);
return;
}
mvwaddstr(win, row, column, s->buf);
s->misc++;
}
static struct user_input_state status_state = {
.offset = 0,
.completion = completion,
.draw = status_draw
};
void user_input_set_status_state(const char *status) {
current_state = &status_state;
reset_state(current_state);
current_state->misc = 0;
strncpy(current_state->buf, status, sizeof(current_state->buf));
current_state->buf[sizeof(current_state->buf) - 1] = '\0';
}
void user_input_set_state(struct user_input_state *state) {
current_state = state;
}
bool user_input_process(void *tinst) {
if(&error_state == current_state) {
usleep(500000);
return false;
}
if(&status_state == current_state) {
return false;
}
int c = getch();
if(ERR == c) {
int flags, modflags, readerrno = 0;
char tmp;
ssize_t r;
flags = fcntl(STDIN_FILENO, F_GETFL, 0);
modflags = flags | O_NONBLOCK;
if(-1 == fcntl(STDIN_FILENO, F_SETFL, modflags)) {
perror("fcntl");
exit(EXIT_FAILURE);
}
r = read(STDIN_FILENO, &tmp, sizeof(tmp));
readerrno = errno;
if(0 == r) {
exit(EXIT_FAILURE);
}
if(-1 == fcntl(STDIN_FILENO, F_SETFL, flags)) {
perror("fcntl");
exit(EXIT_FAILURE);
}
if(-1 == r && EAGAIN == readerrno) {
return false;
}
c = tmp;
}
if(current_state) {
if( 127 == c) {
if(current_state->offset > 0) {
current_state->offset--;
current_state->buf[current_state->offset] = '\0';
}
} else if('\r' == c) {
current_state->buf[current_state->offset] = '\0';
current_state->completion(tinst, current_state);
top_insert(tinst);
top_draw(tinst);
} else {
if(current_state->offset < (sizeof(current_state->buf) - 2)) {
current_state->buf[current_state->offset++] = c;
current_state->buf[current_state->offset] = '\0';
}
}
return true;
}
switch(c) {
case '?':
user_input_set_state(&top_user_input_help_state);
reset_state(current_state);
break;
case 'c':
user_input_set_state(&top_user_input_mode_state);
reset_state(current_state);
break;
case 'o':
user_input_set_state(&top_user_input_order_state);
reset_state(current_state);
break;
case 'O':
user_input_set_state(&top_user_input_secondary_order_state);
reset_state(current_state);
break;
case 'r':
top_prefs_set_mmr(!top_prefs_get_mmr());
user_input_set_status_state(top_prefs_get_mmr() ?
"Report process memory object maps."
:
"Do not report process memory object maps.");
break;
case 's':
user_input_set_state(&top_user_input_sleep_state);
reset_state(current_state);
break;
case 'S':
user_input_set_state(&top_user_input_signal_state);
reset_state(current_state);
break;
case 'U':
user_input_set_state(&top_user_input_user_state);
reset_state(current_state);
break;
case 'q':
case 'Q':
exit(EXIT_SUCCESS);
break;
default:
if(current_state) {
reset_state(current_state);
return true;
}
}
if( '\x0c' == c || ' ' == c || '\r' == c) {
top_insert(tinst);
top_draw(tinst);
}
return true;
}
static int row, column;
void user_input_set_position(int r, int c) {
row = r;
column = c;
}
void user_input_draw(void *tinst, WINDOW *win) {
if(current_state && current_state->draw) {
current_state->draw(tinst, current_state, win, row, column);
}
}