X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/bef1210245bb3180a57f26405369654eaa477f63..HEAD:/lunaix-os/hal/term/lcntls/lcntl.c diff --git a/lunaix-os/hal/term/lcntls/lcntl.c b/lunaix-os/hal/term/lcntls/lcntl.c index 0802318..fb855cc 100644 --- a/lunaix-os/hal/term/lcntls/lcntl.c +++ b/lunaix-os/hal/term/lcntls/lcntl.c @@ -11,30 +11,85 @@ #include #include +#include "lcntl.h" + #include #include static inline void -raise_sig(struct term* at_term, struct linebuffer* lbuf, int sig) +init_lcntl_state(struct lcntl_state* state, + struct term* tdev, enum lcntl_dir direction) { - term_sendsig(at_term, SIGINT); - lbuf->sflags |= LSTATE_SIGRAISE; + *state = (struct lcntl_state) { + .tdev = tdev, + ._lf = tdev->lflags, + ._cf = tdev->cflags, + .direction = direction, + .echobuf = tdev->line_out.current, + }; + + struct linebuffer* lb; + if (direction == INBOUND) { + state->_if = tdev->iflags; + lb = &tdev->line_in; + } + else { + state->_of = tdev->oflags; + lb = &tdev->line_out; + } + + state->inbuf = lb->current; + state->outbuf = lb->next; + state->active_line = lb; } -static inline int must_inline optimize("-fipa-cp-clone") -lcntl_transform_seq(struct term* tdev, struct linebuffer* lbuf, bool out) +static inline void +raise_sig(struct lcntl_state* state, int sig) { - struct rbuffer* raw = lbuf->current; - struct rbuffer* cooked = lbuf->next; - struct rbuffer* output = tdev->line_out.current; + term_sendsig(state->tdev, sig); + lcntl_raise_line_event(state, LEVT_SIGRAISE); +} - int i = 0, _if = tdev->iflags & -!out, _of = tdev->oflags & -!!out, - _lf = tdev->lflags; - int allow_more = 1, latest_eol = cooked->ptr; - char c; +static inline char +__remap_character(struct lcntl_state* state, char c) +{ + if (c == '\r') { + if ((state->_if & _ICRNL) || (state->_of & _OCRNL)) { + return '\n'; + } + } + else if (c == '\n') { + if ((state->_if & _INLCR) || (state->_of & (_ONLRET))) { + return '\r'; + } + } + else if ('a' <= c && c <= 'z') { + if ((state->_if & _IUCLC)) { + return c | 0b100000; + } else if ((state->_of & _OLCUC)) { + return c & ~0b100000; + } + } + + return c; +} - int (*lcntl_slave_put)(struct term*, struct linebuffer*, char) = - tdev->lcntl->process_and_put; +static inline void +lcntl_echo_char(struct lcntl_state* state, char c) +{ + rbuffer_put(state->echobuf, c); +} + +int +__ansi_actcontrol(struct lcntl_state* state, char chr); + +static inline int must_inline +lcntl_transform_seq(struct lcntl_state* state) +{ + struct term* tdev = state->tdev; + char c; + int i = 0; + bool full = false; #define EOL tdev->cc[_VEOL] #define EOF tdev->cc[_VEOF] @@ -44,114 +99,115 @@ lcntl_transform_seq(struct term* tdev, struct linebuffer* lbuf, bool out) #define QUIT tdev->cc[_VQUIT] #define SUSP tdev->cc[_VSUSP] - if (!out) { - // Keep all cc's (except VMIN & VTIME) up to L2 cache. - for (size_t i = 0; i < _VMIN; i++) { - prefetch_rd(&tdev->cc[i], 2); - } - } + while (!lcntl_test_flag(state, LCNTLF_STOP)) + { + lcntl_unset_flag(state, LCNTLF_SPECIAL_CHAR); - while (rbuffer_get(raw, &c) && allow_more) { - - if (c == '\r' && ((_if & _ICRNL) || (_of & _OCRNL))) { - c = '\n'; - } else if (c == '\n') { - if ((_if & _INLCR) || (_of & (_ONLRET))) { - c = '\r'; - } + if (!rbuffer_get(state->inbuf, &c)) { + break; } + c = __remap_character(state, c); + if (c == '\0') { - if ((_if & _IGNBRK)) { + if ((state->_if & _IGNBRK)) { continue; } - if ((_if & _BRKINT)) { - raise_sig(tdev, lbuf, SIGINT); + if ((state->_if & _BRKINT)) { + raise_sig(state, SIGINT); break; } } - if ('a' <= c && c <= 'z') { - if ((_if & _IUCLC)) { - c = c | 0b100000; - } else if ((_of & _OLCUC)) { - c = c & ~0b100000; - } - } - - if (out) { + if (lcntl_outbound(state)) { goto do_out; } if (c == '\n') { - latest_eol = cooked->ptr + 1; - if ((_lf & _ECHONL)) { - rbuffer_put(output, c); + if (lcntl_check_echo(state, _ECHONL)) { + lcntl_echo_char(state, c); } } // For input procesing + lcntl_set_flag(state, LCNTLF_SPECIAL_CHAR); + if (c == '\n' || c == EOL) { - lbuf->sflags |= LSTATE_EOL; - } else if (c == EOF) { - lbuf->sflags |= LSTATE_EOF; - rbuffer_clear(raw); - break; - } else if (c == INTR) { - raise_sig(tdev, lbuf, SIGINT); - } else if (c == QUIT) { - raise_sig(tdev, lbuf, SIGKILL); - break; - } else if (c == SUSP) { - raise_sig(tdev, lbuf, SIGSTOP); - } else if (c == ERASE) { - if (!rbuffer_erase(cooked)) - continue; - } else if (c == KILL) { - // TODO shrink the rbuffer - } else { - goto keep; + lcntl_raise_line_event(state, LEVT_EOL); } - - if ((_lf & _ECHOE) && c == ERASE) { - rbuffer_put(output, '\x8'); - rbuffer_put(output, ' '); - rbuffer_put(output, '\x8'); + else if (c == EOF) { + lcntl_raise_line_event(state, LEVT_EOF); + lcntl_set_flag(state, LCNTLF_CLEAR_INBUF); + lcntl_set_flag(state, LCNTLF_STOP); } - if ((_lf & _ECHOK) && c == KILL) { - rbuffer_put(output, c); - rbuffer_put(output, '\n'); + else if (c == INTR) { + raise_sig(state, SIGINT); + lcntl_set_flag(state, LCNTLF_CLEAR_OUTBUF); } - - continue; - - keep: - if ((_lf & _ECHO)) { - rbuffer_put(output, c); + else if (c == QUIT) { + raise_sig(state, SIGKILL); + lcntl_set_flag(state, LCNTLF_CLEAR_OUTBUF); + lcntl_set_flag(state, LCNTLF_STOP); + } + else if (c == SUSP) { + raise_sig(state, SIGSTOP); + } + else if (c == ERASE) { + if (rbuffer_erase(state->outbuf) && + lcntl_check_echo(state, _ECHOE)) + { + lcntl_echo_char(state, '\x8'); + lcntl_echo_char(state, ' '); + lcntl_echo_char(state, '\x8'); + } + continue; + } + else if (c == KILL) { + lcntl_set_flag(state, LCNTLF_CLEAR_OUTBUF); + } + else { + lcntl_unset_flag(state, LCNTLF_SPECIAL_CHAR); } - goto put_char; + if (lcntl_check_echo(state, _ECHOK) && c == KILL) { + lcntl_echo_char(state, c); + lcntl_echo_char(state, '\n'); + } do_out: - if (c == '\n' && (_of & _ONLCR)) { - rbuffer_put(cooked, '\r'); + if (c == '\n' && (state->_of & _ONLCR)) { + full = !rbuffer_put_nof(state->outbuf, '\r'); } - put_char: - if (!out && (_lf & _IEXTEN) && lcntl_slave_put) { - allow_more = lcntl_slave_put(tdev, lbuf, c); - } else { - allow_more = rbuffer_put(cooked, c); + if (!full) { + if (lcntl_inbound(state) && (state->_lf & _IEXTEN)) { + full = !__ansi_actcontrol(state, c); + } + else { + full = !lcntl_put_char(state, c); + } + } + + if (lcntl_test_flag(state, LCNTLF_CLEAR_INBUF)) { + rbuffer_clear(state->inbuf); + lcntl_unset_flag(state, LCNTLF_CLEAR_INBUF); } + + if (lcntl_test_flag(state, LCNTLF_CLEAR_OUTBUF)) { + rbuffer_clear(state->outbuf); + lcntl_unset_flag(state, LCNTLF_CLEAR_OUTBUF); + } + + i++; } - if (!out && !rbuffer_empty(output) && !(_lf & _NOFLSH)) { + if (state->direction != OUTBOUND && !(state->_lf & _NOFLSH)) { term_flush(tdev); } - line_flip(lbuf); + line_flip(state->active_line); return i; } @@ -159,11 +215,31 @@ lcntl_transform_seq(struct term* tdev, struct linebuffer* lbuf, bool out) int lcntl_transform_inseq(struct term* tdev) { - return lcntl_transform_seq(tdev, &tdev->line_in, false); + struct lcntl_state state; + + init_lcntl_state(&state, tdev, INBOUND); + return lcntl_transform_seq(&state); } int lcntl_transform_outseq(struct term* tdev) { - return lcntl_transform_seq(tdev, &tdev->line_out, true); + struct lcntl_state state; + + init_lcntl_state(&state, tdev, OUTBOUND); + return lcntl_transform_seq(&state); +} + +int +lcntl_put_char(struct lcntl_state* state, char c) +{ + if (lcntl_check_echo(state, _ECHO)) { + lcntl_echo_char(state, c); + } + + if (!lcntl_test_flag(state, LCNTLF_SPECIAL_CHAR)) { + return rbuffer_put_nof(state->outbuf, c); + } + + return 1; } \ No newline at end of file