+static inline int
+csi_starter (int c)
+{
+ switch (c)
+ {
+ case '[':
+ return 1;
+ }
+ return 0;
+}
+
+static inline int
+in_margins (VT102 * v, CRT_Pos p)
+{
+ if (v->pos.x < v->top_margin.x)
+ return 0;
+ if (v->pos.y < v->top_margin.y)
+ return 0;
+
+ if (v->pos.x > v->bottom_margin.x)
+ return 0;
+ if (v->pos.y > v->bottom_margin.y)
+ return 0;
+
+ return 1;
+}
+
+void
+vt102_log_line (Context * c, int line)
+{
+ CRT_Pos e = { VT102_COLS - 1, line };
+ CRT_Pos p = { 0, line };
+ char logbuf[VT102_COLS + 1];
+
+ if (!c->l)
+ return;
+
+
+ for (; e.x > 0; --e.x)
+ {
+ if (c->v->crt.screen[CRT_ADDR_POS (&e)].chr != ' ')
+ break;
+ }
+
+ for (; p.x <= e.x; ++p.x)
+ {
+ int ch = c->v->crt.screen[CRT_ADDR_POS (&p)].chr;
+ if (ch < 32)
+ ch = ' ';
+ if (ch > 126)
+ ch = ' ';
+ logbuf[p.x] = ch;
+ }
+ logbuf[p.x] = 0;
+
+ c->l->log (c->l, logbuf);
+}
+
+/*Called for every upward scroll with same args*/
+void
+vt102_history (Context * c, CRT_Pos t, CRT_Pos b)
+{
+/*Only log if it scrolls off the top*/
+ if (t.y)
+ return;
+
+ t.x = 0;
+ history_add (c->h, &(c->v->crt.screen[CRT_ADDR_POS (&t)]));
+}
+
+void
+vt102_clip_cursor (VT102 * v, CRT_Pos tl, CRT_Pos br)
+{
+ if (v->pos.x < tl.x)
+ v->pos.x = tl.x;
+ if (v->pos.y < tl.y)
+ v->pos.y = tl.y;
+
+ if (v->pos.x > br.x)
+ v->pos.x = br.x;
+ if (v->pos.y > br.y)
+ v->pos.y = br.y;
+}
+
+
+void
+vt102_cursor_normalize (VT102 * v)
+{
+ CRT_Pos *top, *bottom;
+
+ if (v->private_modes[VT102_PRIVATE_MODE_ORIGIN_MODE])
+ {
+ vt102_clip_cursor (v, v->top_margin, v->bottom_margin);
+ }
+ else
+ {
+ vt102_clip_cursor (v, v->screen_start, v->screen_end);
+ }
+}
+
+
+void
+vt102_cursor_carriage_return (VT102 * v)
+{
+ /*FISH*/ v->pos.x = v->top_margin.x;
+ v->pending_wrap = 0;
+}
+
+void
+vt102_cursor_advance_line (Context * c)
+{
+ VT102 *v = c->v;
+ int couldscroll = in_margins (v, v->pos);
+
+/*have wraped off end of last line in scrolling region */
+/* (|| not necessary, but shuts compiler up */
+ if (((v->pos.y == v->bottom_margin.y) || (v->pos.y == v->screen_end.y)) &&
+ (couldscroll))
+ {
+ vt102_log_line (c, v->pos.y);
+
+ vt102_history (c, v->top_margin, v->bottom_margin);
+
+ crt_scroll_up (&v->crt, v->top_margin, v->bottom_margin, 1);
+ return;
+ }
+
+ v->pos.y++;
+ v->pending_wrap = 0;
+}
+
+
+void
+vt102_cursor_advance (Context * c)
+{
+ VT102 *v = c->v;
+
+ if (v->pos.x < v->bottom_margin.x)
+ {
+/*Normal advance*/
+ v->pos.x++;
+ v->pending_wrap = 0;
+ return;
+ }
+ v->pending_wrap++;
+}
+
+
+void
+vt102_do_pending_wrap (Context * c)
+{
+ VT102 *v = c->v;
+ int couldscroll = in_margins (v, v->pos);
+ int autowrap = v->private_modes[VT102_PRIVATE_MODE_AUTO_WRAP];
+
+ if (!v->pending_wrap)
+ return;
+
+#if 0
+ fprintf (stderr, "ca: (%d,%d) autowrap %d couldscroll %d\n", v->pos.x,
+ v->pos.y, autowrap, couldscroll);
+#endif
+
+/*End of line but no autowrap, nothing to do*/
+ if (!autowrap)
+ return;
+
+/*End of screen and not allowed to scroll, nothing to do*/
+ if ((v->pos.y == v->screen_end.y) && (!couldscroll))
+ return;
+
+ if (couldscroll)
+ {
+ v->pos.x = v->top_margin.x;
+ }
+ else
+ {
+ v->pos.x = 0;
+ }
+
+ vt102_cursor_advance_line (c);
+}
+
+
+void
+vt102_cursor_retard (VT102 * v)
+{
+ if (v->pos.x != v->top_margin.x)
+ v->pos.x--;
+
+ v->pending_wrap = 0;
+}
+
+void
+vt102_reset_tabs (VT102 * v)
+{
+ int i;
+
+ memset (v->tabs, 0, sizeof (v->tabs));
+
+ for (i = 0; i < VT102_COLS; i += 8)
+ {
+ v->tabs[i]++;
+ }
+}
+void
+vt102_cursor_advance_tab (VT102 * v)
+{
+ if (v->pos.x == v->bottom_margin.x)
+ return;
+ while (v->pos.x < v->bottom_margin.x)
+ {
+ v->pos.x++;
+ if (v->tabs[v->pos.x])
+ break;
+ }
+ v->pending_wrap = 0;
+}
+
+vt102_cursor_home (VT102 * v)
+{
+ v->pos = v->top_margin;
+ vt102_cursor_normalize (v);
+ v->pending_wrap = 0;
+
+}
+
+vt102_cursor_absolute (VT102 * v, int x, int y)
+{
+ if (v->private_modes[VT102_PRIVATE_MODE_ORIGIN_MODE])
+ {
+ v->pos.x = x + v->top_margin.x;
+ v->pos.y = y + v->top_margin.x;
+ }
+ else
+ {
+ v->pos.x = x;
+ v->pos.y = y;
+ }
+ vt102_cursor_normalize (v);
+ v->pending_wrap = 0;
+}
+
+vt102_cursor_relative (VT102 * v, int x, int y)
+{
+ v->pos.x += x;
+ v->pos.y += y;
+ vt102_cursor_normalize (v);
+ v->pending_wrap = 0;
+}
+
+
+
+void
+vt102_delete_from_line (VT102 * v, CRT_Pos p)
+{
+ int n = v->bottom_margin.x - p.x;
+
+ if (n < 0)
+ return;
+
+ if (n)
+ {
+
+ memmove (&v->crt.screen[CRT_ADDR_POS (&p)],
+ &v->crt.screen[CRT_ADDR_POS (&p) + 1], sizeof (CRT_CA) * n);
+ }
+
+ v->crt.screen[CRT_ADDR (p.y, v->bottom_margin.x)].chr = ' ';
+/*But not attr due to vt102 bug*/
+}
+
+void
+vt102_insert_into_line (VT102 * v, CRT_Pos p)
+{
+ int n = v->bottom_margin.x - p.x;
+
+ if (n < 0)
+ return;
+
+ if (n)
+ {
+
+ memmove (&v->crt.screen[CRT_ADDR_POS (&p) + 1],
+ &v->crt.screen[CRT_ADDR_POS (&p)], sizeof (CRT_CA) * n);
+ }
+
+ v->crt.screen[CRT_ADDR (p.y, v->bottom_margin.x)].chr = ' ';
+ v->crt.screen[CRT_ADDR (p.y, v->bottom_margin.x)].attr = CRT_ATTR_NORMAL;
+ v->crt.screen[CRT_ADDR (p.y, v->bottom_margin.x)].color = CRT_COLOR_NORMAL;
+}
+
+
+
+void
+vt102_change_mode (VT102 * v, int private, char *ns, int set)
+{
+ int m;
+
+
+ if (*ns)
+ {
+ m = atoi (ns);
+ }
+ else
+ {
+ m = 1;
+ }
+
+ if (m < 0)
+ return;
+ if (m >= VT102_NMODES)
+ return;
+
+ if (private)
+ {
+ v->private_modes[m] = set;
+ switch (m)
+ {
+ case VT102_PRIVATE_MODE_CURSOR_MODE:
+ if (v->application_keypad_mode)
+ v->private_modes[m] = 0;
+#if 0
+ fprintf (stderr, "APPLICATION CURSOR MODE %d wanted %d\n",
+ v->private_modes[m], set);
+#endif
+ break;
+ case VT102_PRIVATE_MODE_ORIGIN_MODE:
+ vt102_cursor_home (v);
+ break;
+ }
+
+ }
+ else
+ v->modes[m] = set;
+
+#if 0
+ fprintf (stderr, "mode set=%d private=%d num=%d\n", set, private, m);
+#endif
+}
+
+void
+vt102_parse_mode_string (VT102 * v, char *buf, int len)