static inline void
raise_sig(struct term* at_term, struct linebuffer* lbuf, int sig)
{
- term_sendsig(at_term, SIGINT);
+ term_sendsig(at_term, sig);
lbuf->sflags |= LSTATE_SIGRAISE;
}
-static inline int
-lcntl_invoke_slaves(struct term* tdev, struct linebuffer* lbuf, char c)
-{
- int allow_more = 0;
- struct term_lcntl *lcntl, *n;
- llist_for_each(lcntl, n, &tdev->lcntl_stack, lcntls)
- {
- allow_more = lcntl->process_and_put(tdev, lbuf, c);
- if (!allow_more) {
- break;
- }
-
- line_flip(lbuf);
- }
-
- return allow_more;
-}
-
-static inline int optimize("ipa-cp-clone")
+static inline int must_inline optimize("-fipa-cp-clone")
lcntl_transform_seq(struct term* tdev, struct linebuffer* lbuf, bool out)
{
struct rbuffer* raw = lbuf->current;
_lf = tdev->lflags;
int allow_more = 1, latest_eol = cooked->ptr;
char c;
- bool should_flush = false;
+
+ int (*lcntl_slave_put)(struct term*, struct linebuffer*, char) =
+ tdev->lcntl->process_and_put;
#define EOL tdev->cc[_VEOL]
#define EOF tdev->cc[_VEOF]
#define QUIT tdev->cc[_VQUIT]
#define SUSP tdev->cc[_VSUSP]
+#define putc_safe(rb, chr) \
+ ({ \
+ if (!rbuffer_put_nof(rb, chr)) { \
+ break; \
+ } \
+ })
+
if (!out) {
// Keep all cc's (except VMIN & VTIME) up to L2 cache.
for (size_t i = 0; i < _VMIN; i++) {
}
}
- while (rbuffer_get(raw, &c) && allow_more) {
+ while (allow_more && rbuffer_get(raw, &c)) {
if (c == '\r' && ((_if & _ICRNL) || (_of & _OCRNL))) {
c = '\n';
} else if (c == '\n') {
- if ((_if & _INLCR) || (_of & (_ONLRET | _ONLCR))) {
+ if ((_if & _INLCR) || (_of & (_ONLRET))) {
c = '\r';
}
}
if (c == '\0') {
+ if ((_if & _IGNBRK)) {
+ continue;
+ }
+
if ((_if & _BRKINT)) {
raise_sig(tdev, lbuf, SIGINT);
break;
}
-
- if ((_if & _IGNBRK)) {
- continue;
- }
}
if ('a' <= c && c <= 'z') {
}
}
+ if (out) {
+ goto do_out;
+ }
+
if (c == '\n') {
latest_eol = cooked->ptr + 1;
- if (!out && (_lf & _ECHONL)) {
+ if ((_lf & _ECHONL)) {
rbuffer_put(output, c);
}
- should_flush = true;
- }
-
- if (out) {
- goto put_char;
}
// For input procesing
if (c == '\n' || c == EOL) {
lbuf->sflags |= LSTATE_EOL;
- goto keep;
} else if (c == EOF) {
lbuf->sflags |= LSTATE_EOF;
rbuffer_clear(raw);
} else if (c == SUSP) {
raise_sig(tdev, lbuf, SIGSTOP);
} else if (c == ERASE) {
- rbuffer_erase(cooked);
+ if (!rbuffer_erase(cooked))
+ continue;
+ } else if (c == KILL) {
+ // TODO shrink the rbuffer
} else {
goto keep;
}
+ if ((_lf & _ECHOE) && c == ERASE) {
+ rbuffer_put(output, '\x8');
+ rbuffer_put(output, ' ');
+ rbuffer_put(output, '\x8');
+ }
+ if ((_lf & _ECHOK) && c == KILL) {
+ rbuffer_put(output, c);
+ rbuffer_put(output, '\n');
+ }
+
continue;
keep:
if ((_lf & _ECHO)) {
rbuffer_put(output, c);
}
- if ((_lf & _ECHOE) && c == ERASE) {
- rbuffer_erase(output);
- }
- if ((_lf & _ECHOK) && c == KILL) {
- rbuffer_put(output, c);
- rbuffer_put(output, '\n');
+
+ goto put_char;
+
+ do_out:
+ if (c == '\n' && (_of & _ONLCR)) {
+ putc_safe(cooked, '\r');
}
put_char:
- allow_more = rbuffer_put(cooked, c);
- }
-
- if (out || (_lf & _IEXTEN)) {
- line_flip(lbuf);
- lcntl_invoke_slaves(tdev, lbuf, c);
+ if (!out && (_lf & _IEXTEN) && lcntl_slave_put) {
+ allow_more = lcntl_slave_put(tdev, lbuf, c);
+ } else {
+ allow_more = rbuffer_put_nof(cooked, c);
+ }
}
- if (should_flush && !(_lf & _NOFLSH)) {
+ if (!out && !rbuffer_empty(output) && !(_lf & _NOFLSH)) {
term_flush(tdev);
}
+ line_flip(lbuf);
+
return i;
}
int
lcntl_transform_outseq(struct term* tdev)
{
- return lcntl_transform_seq(tdev, &tdev->line_in, true);
+ return lcntl_transform_seq(tdev, &tdev->line_out, true);
}
\ No newline at end of file