Added copyright notices to files
[librote.git] / inject.c
blob9d3c431758b8cc054c4e773bcb6384769a8db3c0
1 /*
2 LICENSE INFORMATION:
3 This program is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Lesser General Public
5 License (LGPL) as published by the Free Software Foundation.
7 Please refer to the COPYING file for more information.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 Copyright (c) 2004 Bruno T. C. de Oliveira
22 #include "rote.h"
23 #include "roteprivate.h"
24 #include "inject_csi.h"
25 #include <string.h>
27 static void cursor_line_down(RoteTerm *rt) {
28 int i;
29 rt->crow++;
30 rt->curpos_dirty = true;
31 if (rt->crow <= rt->pd->scrollbottom) return;
33 /* must scroll the scrolling region up by 1 line, and put cursor on
34 * last line of it */
35 rt->crow = rt->pd->scrollbottom;
37 for (i = rt->pd->scrolltop; i < rt->pd->scrollbottom; i++) {
38 rt->line_dirty[i] = true;
39 memcpy(rt->cells[i], rt->cells[i+1], sizeof(RoteCell) * rt->cols);
42 rt->line_dirty[rt->pd->scrollbottom] = true;
44 /* clear last row of the scrolling region */
45 for (i = 0; i < rt->cols; i++) {
46 rt->cells[rt->pd->scrollbottom][i].ch = 0x20;
47 rt->cells[rt->pd->scrollbottom][i].attr = 0x70;
52 static void cursor_line_up(RoteTerm *rt) {
53 int i;
54 rt->crow--;
55 rt->curpos_dirty = true;
56 if (rt->crow >= rt->pd->scrolltop) return;
58 /* must scroll the scrolling region up by 1 line, and put cursor on
59 * first line of it */
60 rt->crow = rt->pd->scrolltop;
62 for (i = rt->pd->scrollbottom; i > rt->pd->scrolltop; i--) {
63 rt->line_dirty[i] = true;
64 memcpy(rt->cells[i], rt->cells[i-1], sizeof(RoteCell) * rt->cols);
67 rt->line_dirty[rt->pd->scrolltop] = true;
69 /* clear first row of the scrolling region */
70 for (i = 0; i < rt->cols; i++) {
71 rt->cells[rt->pd->scrolltop][i].ch = 0x20;
72 rt->cells[rt->pd->scrolltop][i].attr = 0x70;
77 static inline void put_normal_char(RoteTerm *rt, char c) {
78 rt->cells[rt->crow][rt->ccol].ch = c;
79 rt->cells[rt->crow][rt->ccol].attr = rt->curattr;
80 rt->ccol++;
82 rt->line_dirty[rt->crow] = true;
83 rt->curpos_dirty = true;
85 if (rt->ccol >= rt->cols) {
86 rt->ccol = 0;
87 cursor_line_down(rt);
91 static inline void put_graphmode_char(RoteTerm *rt, char c) {
92 char nc;
93 /* do some very pitiful translation to regular ascii chars */
94 switch (c) {
95 case 'j': case 'k': case 'l': case 'm': case 'n': case 't':
96 case 'u': case 'v': case 'w':
97 nc = '+'; break;
98 case 'x':
99 nc = '|'; break;
100 default:
101 nc = '%';
104 put_normal_char(rt, nc);
107 static inline void new_escape_sequence(RoteTerm *rt) {
108 rt->pd->escaped = true;
109 rt->pd->esbuf_len = 0;
110 rt->pd->esbuf[0] = '\0';
113 static inline void cancel_escape_sequence(RoteTerm *rt) {
114 rt->pd->escaped = false;
115 rt->pd->esbuf_len = 0;
116 rt->pd->esbuf[0] = '\0';
119 static void handle_control_char(RoteTerm *rt, char c) {
120 switch (c) {
121 case '\r': rt->ccol = 0; break; /* carriage return */
122 case '\n': /* line feed */
123 rt->ccol = 0; cursor_line_down(rt);
124 rt->curpos_dirty = true;
125 break;
126 case '\b': /* backspace */
127 if (rt->ccol > 0) rt->ccol--;
128 rt->curpos_dirty = true;
129 break;
130 case '\t': /* tab */
131 while (rt->ccol % 8) put_normal_char(rt, ' ');
132 break;
133 case '\x1B': /* begin escape sequence (aborting previous one if any) */
134 new_escape_sequence(rt);
135 break;
136 case '\x0E': /* enter graphical character mode */
137 rt->pd->graphmode = true;
138 break;
139 case '\x0F': /* exit graphical character mode */
140 rt->pd->graphmode = false;
141 break;
142 case '\x9B': /* CSI character. Equivalent to ESC [ */
143 new_escape_sequence(rt);
144 rt->pd->esbuf[rt->pd->esbuf_len++] = '[';
145 break;
146 case '\x18': case '\x1A': /* these interrupt escape sequences */
147 cancel_escape_sequence(rt);
148 break;
149 case '\a': /* bell */
150 /* do nothing for now... maybe a visual bell would be nice? */
151 break;
152 #ifdef DEBUG
153 default:
154 fprintf(stderr, "Unrecognized control char: %d (^%c)\n", c, c + '@');
155 break;
156 #endif
160 static inline bool is_valid_csi_ender(char c) {
161 return (c >= 'a' && c <= 'z') ||
162 (c >= 'A' && c <= 'Z') ||
163 c == '@' || c == '`';
166 static void try_interpret_escape_seq(RoteTerm *rt) {
167 char firstchar = rt->pd->esbuf[0];
168 char lastchar = rt->pd->esbuf[rt->pd->esbuf_len-1];
170 if (!firstchar) return; /* too early to do anything */
172 if (rt->pd->handler) {
173 /* call custom handler */
174 #ifdef DEBUG
175 fprintf(stderr, "Calling custom handler for ES <%s>.\n", rt->pd->esbuf);
176 #endif
178 int answer = (*(rt->pd->handler))(rt, rt->pd->esbuf);
179 if (answer == ROTE_HANDLERESULT_OK) {
180 /* successfully handled */
181 #ifdef DEBUG
182 fprintf(stderr, "Handler returned OK. Done with escape sequence.\n");
183 #endif
185 cancel_escape_sequence(rt);
186 return;
188 else if (answer == ROTE_HANDLERESULT_NOTYET) {
189 /* handler might handle it when more characters are appended to
190 * it. So for now we don't interpret it */
191 #ifdef DEBUG
192 fprintf(stderr, "Handler returned NOTYET. Waiting for more chars.\n");
193 #endif
195 return;
198 /* If we got here then answer == ROTE_HANDLERESULT_NOWAY */
199 /* handler said it can't handle that escape sequence,
200 * but we can still try handling it ourselves, so
201 * we proceed normally. */
202 #ifdef DEBUG
203 fprintf(stderr, "Handler returned NOWAY. Trying our handlers.\n");
204 #endif
207 /* interpret ESC-M as reverse line-feed */
208 if (firstchar == 'M') {
209 cursor_line_up(rt);
210 cancel_escape_sequence(rt);
211 return;
214 if (firstchar != '[' && firstchar != ']') {
215 /* unrecognized escape sequence. Let's forget about it. */
216 #ifdef DEBUG
217 fprintf(stderr, "Unrecognized ES: <%s>\n", rt->pd->esbuf);
218 #endif
220 cancel_escape_sequence(rt);
221 return;
224 if (firstchar == '[' && is_valid_csi_ender(lastchar)) {
225 /* we have a csi escape sequence: interpret it */
226 rote_es_interpret_csi(rt);
227 cancel_escape_sequence(rt);
229 else if (firstchar == ']' && lastchar == '\a') {
230 /* we have an xterm escape sequence: interpret it */
232 /* rote_es_interpret_xterm_es(rt); -- TODO!*/
233 #ifdef DEBUG
234 fprintf(stderr, "Ignored XTerm ES.\n");
235 #endif
236 cancel_escape_sequence(rt);
239 /* if the escape sequence took up all available space and could
240 * not yet be parsed, abort it */
241 if (rt->pd->esbuf_len + 1 >= ESEQ_BUF_SIZE) cancel_escape_sequence(rt);
244 void rote_vt_inject(RoteTerm *rt, const char *data, int len) {
245 int i;
246 for (i = 0; i < len; i++, data++) {
247 if (*data == 0) continue; /* completely ignore NUL */
248 if (*data >= 1 && *data <= 31) {
249 handle_control_char(rt, *data);
250 continue;
253 if (rt->pd->escaped && rt->pd->esbuf_len < ESEQ_BUF_SIZE) {
254 /* append character to ongoing escape sequence */
255 rt->pd->esbuf[rt->pd->esbuf_len] = *data;
256 rt->pd->esbuf[++rt->pd->esbuf_len] = 0;
258 try_interpret_escape_seq(rt);
260 else if (rt->pd->graphmode)
261 put_graphmode_char(rt, *data);
262 else
263 put_normal_char(rt, *data);