mirror of https://github.com/buserror/mii_emu.git
274 lines
6.5 KiB
C
274 lines
6.5 KiB
C
/*
|
|
* mish_priv.h
|
|
*
|
|
* Copyright (C) 2020 Michel Pollet <buserror@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#ifndef LIBMISH_SRC_MISH_PRIV_H_
|
|
#define LIBMISH_SRC_MISH_PRIV_H_
|
|
|
|
#include <sys/select.h>
|
|
#include <stdint.h>
|
|
#include <pthread.h>
|
|
#include <termios.h>
|
|
#include "bsd_queue.h"
|
|
#include "mish_priv_vt.h"
|
|
#include "mish_priv_line.h"
|
|
|
|
struct mish_t;
|
|
|
|
/*
|
|
* The process_char callback of mish_input_t returns one of these.
|
|
*/
|
|
enum {
|
|
MISH_IN_SKIP = 0, // skip current character (don't store)
|
|
MISH_IN_STORE, // store current character in input buffer
|
|
MISH_IN_SPLIT, // store current line, add it to backlog
|
|
};
|
|
|
|
/*
|
|
* This receives stuff from a file descriptor, 'processes' it, and split it
|
|
* into lines to eventually store new lines into the 'backlog'.
|
|
*/
|
|
typedef struct mish_input_t {
|
|
// lines read from fd are queued in here when \n has been received
|
|
mish_line_queue_t backlog;
|
|
uint32_t is_telnet : 1, flush_on_nl : 1;
|
|
|
|
// return 1 for the character to be stored, 0 for it to be skipped
|
|
int (*process_char)(
|
|
struct mish_t *m,
|
|
struct mish_input_t *i,
|
|
uint8_t ch);
|
|
void * refcon; // reference constant, for the callbacks
|
|
int fd;
|
|
mish_line_p line;
|
|
} mish_input_t, *mish_input_p;
|
|
|
|
/* various internal states for the client */
|
|
enum {
|
|
MISH_CLIENT_INIT_SENT = (1 << 0),
|
|
MISH_CLIENT_HAS_WINDOW_SIZE = (1 << 1),
|
|
MISH_CLIENT_HAS_CURSOR_POS = (1 << 2),
|
|
MISH_CLIENT_UPDATE_PROMPT = (1 << 3),
|
|
MISH_CLIENT_UPDATE_WINDOW = (1 << 4),
|
|
MISH_CLIENT_SCROLLING = (1 << 5),
|
|
MISH_CLIENT_DELETE = (1 << 6),
|
|
};
|
|
|
|
typedef struct mish_client_t {
|
|
TAILQ_ENTRY(mish_client_t) self;
|
|
struct mish_t * mish;
|
|
uint32_t flags;
|
|
|
|
// "coroutine" processing received lines from the stdout/err
|
|
struct {
|
|
void * state; // state for the prompt coroutine
|
|
// _mish_client_interractive_cr() or _mish_client_dumb_cr()
|
|
void (*process)(
|
|
struct mish_t * m,
|
|
struct mish_client_t* c);
|
|
} cr;
|
|
int footer_height; // # static lines at bottom of screen
|
|
int current_vpos;
|
|
mish_line_p bottom;
|
|
// Line we are currently sending (or NULL)
|
|
mish_line_p sending;
|
|
|
|
/*
|
|
* Output sent to the client is made of bits we want to send to move
|
|
* the cursor and so on, and, the actual lines we captured from the program.
|
|
* So a vector list is built as the output is built, and it's made of bits
|
|
* we've copied in "sqb" as well as lines from the mish backlog.
|
|
* Once we deem a good time to output stuff, we send that vector and wait
|
|
* until it's all gone before starting again.
|
|
*/
|
|
struct {
|
|
int fd; // index of fd we writev to
|
|
struct iovec *v; // starts at NULL
|
|
int count;// how many are filled in
|
|
int size; // how many are allocated
|
|
// temporary sequence buffer, for composite output.
|
|
mish_line_p sqb;
|
|
size_t total; // total bytes we sent
|
|
} output;
|
|
|
|
char prompt[64];
|
|
/* Since the prompt will contains more bytes than displayed glyphs,
|
|
* we keep track of the number of glyphs so we can reposition the
|
|
* cursor accurately. */
|
|
int prompt_gc; // prompt real glyph count
|
|
|
|
/*
|
|
* Unfiltered console input from the client. This get stored in there
|
|
* until the input code notices any output has been sent. Then it is
|
|
* passed down to 'vts'
|
|
*/
|
|
mish_input_t input;
|
|
/*
|
|
* this handles the vt sequences received at the command prompt,
|
|
* like direction keys etc -also handles UTF8 sequences- (but doesn't do
|
|
* anything with them). It is also subverted by the telnet decoder to
|
|
* do it's own things, separately.
|
|
* Sequences coming out are processed in mish_client_input.
|
|
*/
|
|
mish_vt_sequence_t vts;
|
|
/*
|
|
* Stuff received from 'input' side gets filtered via 'vts' and
|
|
* stored in this.
|
|
* Once a command has been validated, it is added back to the input
|
|
* backlog to make this client 'history'
|
|
*/
|
|
mish_line_p cmd;
|
|
|
|
struct {
|
|
int w, h; } window_size; // valid if MISH_CLIENT_HAS_WINDOW_SIZE
|
|
struct {
|
|
int x, y; } cursor_pos; // valid if MISH_CLIENT_HAS_CURSOR_POS
|
|
} mish_client_t, *mish_client_p;
|
|
|
|
// supplement the public ones from mish.h
|
|
enum {
|
|
MISH_QUIT = (1 << 31),
|
|
// the process console we started was a tty, so has terminal settings
|
|
MISH_CONSOLE_TTY = (1 << 30),
|
|
};
|
|
|
|
typedef struct mish_t {
|
|
uint32_t flags;
|
|
struct termios orig_termios; // original terminal settings
|
|
int originals[2]; // backup the original 1,2 fds
|
|
/* These are the ones we use to read the output from the main program. */
|
|
mish_input_t origin[2];
|
|
uint64_t stamp_start;
|
|
|
|
TAILQ_HEAD(, mish_client_t) clients;
|
|
mish_client_p console; // client that is also the original terminal.
|
|
|
|
pthread_t capture; // libmish main thread
|
|
pthread_t main; // todo: allow pause/stop/resume?
|
|
|
|
struct {
|
|
mish_line_queue_t log;
|
|
unsigned int size; // number of lines in backlog
|
|
size_t alloc; // number of bytes in the backlog
|
|
} backlog;
|
|
struct {
|
|
int listen; // listen socket
|
|
int port; // port we're listening on
|
|
} telnet;
|
|
// Used by the select thread in mish_capture_select.c
|
|
struct {
|
|
fd_set read, write;
|
|
int max;
|
|
} select;
|
|
} mish_t, *mish_p;
|
|
|
|
mish_client_p
|
|
mish_client_new(
|
|
mish_p m,
|
|
int in,
|
|
int out,
|
|
int is_tty);
|
|
void
|
|
mish_client_delete(
|
|
mish_p m,
|
|
mish_client_p c);
|
|
|
|
/*
|
|
* Sequence buffer handling
|
|
*/
|
|
int
|
|
_mish_send_flush(
|
|
mish_p m,
|
|
mish_client_p c);
|
|
void
|
|
_mish_send_queue(
|
|
mish_client_p c,
|
|
const char * b);
|
|
void
|
|
_mish_send_queue_fmt(
|
|
mish_client_p c,
|
|
const char *fmt, ...);
|
|
void
|
|
_mish_send_queue_line(
|
|
mish_client_p c,
|
|
mish_line_p line );
|
|
|
|
//! Parse current input buffer fro VT sequences, like keys.
|
|
int
|
|
_mish_client_vt_parse_input(
|
|
struct mish_t *m,
|
|
struct mish_input_t *in,
|
|
uint8_t ich);
|
|
|
|
/*
|
|
* This is the main interactive client coroutine. This one is interesting.
|
|
*/
|
|
void
|
|
_mish_client_interractive_cr(
|
|
mish_p m,
|
|
mish_client_p c);
|
|
void
|
|
_mish_client_dumb_cr(
|
|
mish_p m,
|
|
mish_client_p c);
|
|
|
|
uint64_t
|
|
_mish_stamp_ms();
|
|
|
|
/*
|
|
* telnet handling
|
|
*/
|
|
int
|
|
mish_telnet_prepare(
|
|
mish_p m,
|
|
uint16_t port);
|
|
int
|
|
mish_telnet_in_check(
|
|
mish_p m,
|
|
fd_set * r);
|
|
void
|
|
mish_telnet_send_init(
|
|
mish_client_p c);
|
|
int
|
|
_mish_telnet_parse(
|
|
mish_client_p c,
|
|
uint8_t ch);
|
|
|
|
/*
|
|
* input handling
|
|
*/
|
|
void
|
|
_mish_input_init(
|
|
mish_p m,
|
|
mish_input_p in,
|
|
int fd);
|
|
void
|
|
_mish_input_clear(
|
|
mish_p m,
|
|
mish_input_p in);
|
|
int
|
|
_mish_input_read(
|
|
mish_p m,
|
|
fd_set * fds,
|
|
mish_input_p in);
|
|
|
|
/*
|
|
* Capture thread function
|
|
*/
|
|
void *
|
|
_mish_capture_select(
|
|
void *param);
|
|
|
|
/*
|
|
* https://en.wikipedia.org/wiki/ANSI_escape_code#Terminal_output_sequences
|
|
*/
|
|
#define MISH_COLOR_RED "\033[38;5;125m"
|
|
#define MISH_COLOR_GREEN "\033[38;5;28m"
|
|
#define MISH_COLOR_RESET "\033[0m"
|
|
|
|
#endif /* LIBMISH_SRC_MISH_PRIV_H_ */
|