11 vt100
* init_term (int width
, int height
)
13 vt100
*term
= malloc(sizeof(vt100
) + 3 * width
* height
);
16 write_log (LOG_ERROR
, "unable to allocate memory to create terminal %dx%d", width
, height
);
22 term
->cx
= term
->cy
= 0;
23 term
->cmode
= CM_NORM
;
27 term
->prev_char
= ' ';
29 term
->screen
= ((uint8_t*)term
) + sizeof(vt100
);
30 term
->colour
= term
->screen
+ width
* height
;
31 term
->attrib
= term
->colour
+ width
* height
;
32 memset (term
->screen
, ' ', width
* height
);
33 memset (term
->attrib
, 0, width
* height
);
34 memset (term
->colour
, 0, width
* height
);
41 vt100
* resize_term (vt100
*term
, int width
, int height
)
49 // we can't use strtol() because the string doesn't have to be 0-terminated
50 static int get_num (const uint8_t *data
, int len
, int *pos
)
55 for (i
= 0; i
< len
; i
++)
57 if (!isdigit(data
[i
])) break;
58 n
= n
* 10 + data
[i
] - '0';
67 static void process_attr (vt100
*term
, int attr
)
70 if (attr
<= 10) term
->att
= attr
;
73 if (attr
>= 30 && attr
<= 37) term
->col
= (term
->col
& 0xF0) | (attr
- 30);
76 if (attr
>= 40 && attr
<= 47) term
->col
= (term
->col
& 0x0F) | ((attr
- 40) << 4);
81 static void erase_screen (vt100
*term
, int n1
)
83 memset (term
->screen
, ' ', term
->wid
* term
->hgt
);
84 memset (term
->attrib
, 0, term
->wid
* term
->hgt
);
85 memset (term
->colour
, 0, term
->wid
* term
->hgt
);
86 if (n1
!= 2) term
->cx
= term
->cy
= 0;
91 static void erase_line (vt100
*term
, int n1
)
93 int ofs
= term
->wid
* term
->cy
;
96 // [ 0 K or [ K - to the end of line
103 // [ 1 K - to the beginning of line
109 memset (&term
->screen
[ofs
], ' ', l
);
110 memset (&term
->attrib
[ofs
], 0, l
);
111 memset (&term
->colour
[ofs
], 0, l
);
116 static void erase_characters (vt100
*term
, int n1
)
118 int ofs
= term
->wid
* term
->cy
+ term
->cx
;
119 int l
= term
->wid
- term
->cx
;
122 memset (&term
->screen
[ofs
], ' ', l
);
123 memset (&term
->attrib
[ofs
], 0, l
);
124 memset (&term
->colour
[ofs
], 0, l
);
129 // process single non-esc character
130 static void process_char (vt100
*term
, char c
)
139 if (term
->cy
< term
->hgt
- 1) term
->cy
++;
144 if (term
->cx
> 0) term
->cx
--;
149 int ofs
= term
->cy
* term
->wid
+ term
->cx
;
150 term
->screen
[ofs
] = c
;
151 term
->attrib
[ofs
] = term
->att
;
152 term
->colour
[ofs
] = term
->col
;
153 if (++term
->cx
>= term
->wid
)
157 if (term
->cy
< term
->hgt
- 1) term
->cy
++;
168 static int parse_dec (vt100
*term
, int args
, int arg
[MAX_ARGS
])
173 switch (term
->esc
[term
->esc_len
- 1])
175 // [ Y ; X H - goto Y,X
180 term
->cx
= term
->cy
= 0;
184 if (args
!= 2) return -1;
186 if (arg
[0] != 0) arg
[0]--;
187 if (arg
[0] >= 0 && arg
[0] < term
->hgt
) term
->cy
= arg
[0];
188 if (arg
[1] != 0) arg
[1]--;
189 if (arg
[1] >= 0 && arg
[1] < term
->wid
) term
->cx
= arg
[1];
192 // [ nn J or [ J - clear screen
194 if (args
== 0) arg
[0] = 0;
195 erase_screen (term
, arg
[0]);
198 // [ nn K or [ K - erase line
200 if (args
== 0) arg
[0] = 0;
201 erase_line (term
, arg
[0]);
204 // [ N1 m or [ N1 ; N2 m or [ N1 ; N2 ; N3 m - set colour and/or attribute (SGR mode)
206 if (args
== 0) args
= 1, arg
[0] = 0;
208 for (i
= 0; i
< args
; i
++)
210 process_attr (term
, arg
[i
]);
214 // [ nn @ or [ @ - insert blank characters
216 if (args
== 0) arg
[0] = 1;
217 for (i
= 0; i
< arg
[0]; i
++)
219 process_char (term
, ' ');
224 if (args
!= 1) return -1;
225 for (i
= 0; i
< arg
[0]; i
++)
227 process_char (term
, term
->prev_char
);
231 // [ nn A or [ A - move cursor up
233 if (args
== 0 || arg
[0] < 1) arg
[0] = 1;
235 if (term
->cy
< 0) term
->cy
= 0;
238 // [ nn B or [ B - move cursor down
240 if (args
== 0 || arg
[0] < 1) arg
[0] = 1;
242 if (term
->cy
>= term
->hgt
) term
->cy
= term
->hgt
- 1;
245 // [ nn C or [ C - move cursor right
247 if (args
== 0 || arg
[0] < 1) arg
[0] = 1;
249 if (term
->cx
>= term
->wid
) term
->cx
= term
->wid
- 1;
252 // [ nn D or [ D - move cursor left
254 if (args
== 0 || arg
[0] < 1) arg
[0] = 1;
256 if (term
->cx
< 0) term
->cx
= 0;
259 // [ nn X - delete characters
261 if (args
!= 1) return -1;
263 if (arg
[0] == 0) arg
[0] = 1;
264 erase_characters (term
, arg
[0]);
267 // [ nn d - move to specified row
269 if (args
!= 1) return -1;
271 if (arg
[0] != 0) arg
[0]--;
273 if (term
->cy
>= term
->hgt
) term
->cy
= term
->hgt
- 1;
276 // [ nn G - move to specified column
278 if (args
!= 1) return -1;
280 if (arg
[0] != 0) arg
[0]--;
282 if (term
->cx
>= term
->wid
) term
->cx
= term
->wid
- 1;
294 static int parse_dec_priv (vt100
*term
, int args
, int arg
[MAX_ARGS
])
296 switch (term
->esc
[term
->esc_len
- 1])
299 if (args
== 0) return -1;
300 if (arg
[0] == 25) term
->cmode
= CM_NORM
;
304 if (args
== 0) return -1;
305 if (arg
[0] == 25) term
->cmode
= CM_HIDE
;
317 static int parse_esc (vt100
*term
)
323 // XXX something unknown - skip
324 if (!isalnum(term
->esc
[2]))
326 if (term
->esc
[2] == '@' || term
->esc
[2] == '?') p
++;
331 while (args
< MAX_ARGS
)
335 arg
[args
] = get_num(&term
->esc
[p
], term
->esc_len
- p
, &np
);
340 if (term
->esc
[p
- 1] != ';') break;
344 if (term
->esc
[1] == '[')
346 // DEC private mode command
347 if (term
->esc
[2] == '?') return parse_dec_priv(term
, args
, arg
);
349 return parse_dec(term
, args
, arg
);
357 static void process_esc (vt100
*term
)
359 char c
= term
->esc
[term
->esc_len
- 1];
361 // sequence is not complete yet
362 if (!isalpha(c
) && c
!= '@' && c
!= 033) return;
363 if (term
->esc_len
> 2) parse_esc (term
);
370 void term_process (vt100
*term
, const char *data
, int len
)
375 for (i
= 0; i
< len
; i
++)
377 // inside esc seqence
380 term
->esc
[term
->esc_len
++] = data
[i
];
383 // XXX sequence is too long, just dump it to the terminal
384 if (term
->esc_len
>= VT100_ESC_BUF
)
386 for (j
= 0; j
< VT100_ESC_BUF
; j
++)
388 process_char (term
, term
->esc
[j
]);
396 if (data
[i
] == 033) term
->esc
[0] = 0x33, term
->esc_len
= 1;
397 // a normal character
398 else process_char (term
, data
[i
]);
406 static void add_buf (char *buf
, int *pos
, const char *data
, int len
, int fd
)
414 l
= (len
< max
) ? len
: max
;
415 memcpy (&buf
[*pos
], data
, l
);
422 write (fd
, buf
, BUFSZ
);
430 void term_copy_data (vt100
*term
, int fd
)
432 char buf
[BUFSZ
] = "\033[H\033[2J";
433 int i
, pos
= 7, a
, c
, cf
, cb
;
438 // initial colours and attribute
443 pos
+= sprintf(&buf
[pos
], "\033[0;%dm\033[%d;%dm", a
, cb
+ 40, cf
+ 30);
446 for (i
= 0; i
< term
->wid
* term
->hgt
; i
++)
452 if (a
!= term
->attrib
[i
])
455 p2
+= sprintf(&b2
[p2
], "\033[0;%dm", a
);
457 // force colour change since colours are reset
462 if (c
!= term
->colour
[i
])
468 if (cf2
!= cf
&& cb2
!= cb
) p2
+= sprintf(&b2
[p2
], "\033[%d;%dm", cb2
+ 40, cf2
+ 30);
469 else if (cf2
!= cf
) p2
+= sprintf(&b2
[p2
], "\033[%dm", cf2
+ 30);
470 else p2
+= sprintf(&b2
[p2
], "\033[%dm", cb2
+ 40);
476 add_buf (buf
, &pos
, b2
, p2
, fd
);
478 add_buf (buf
, &pos
, (char*)&term
->screen
[i
], 1, fd
);
481 p2
= sprintf(b2
, "\033[%d;%dH", term
->cy
+ 1, term
->cx
+ 1);
482 add_buf (buf
, &pos
, b2
, p2
, fd
);
485 if (term
->cmode
== CM_HIDE
) p2
= sprintf(b2
, "\033[?25l");
486 else p2
= sprintf(b2
, "\033[?25h");
487 add_buf (buf
, &pos
, b2
, p2
, fd
);
489 if (pos
> 0) write (fd
, buf
, pos
);