rename the project into madtty.
[apps/madtty.git] / rote.h
1 /* ROTE - Our Own Terminal Emulation library 
2  * Copyright (c) 2004 Bruno T. C. de Oliveira
3  * All rights reserved
4  *
5  * 2004-08-25
6  */
7
8 /*
9 LICENSE INFORMATION:
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License (LGPL) as published by the Free Software Foundation.
13
14 Please refer to the COPYING file for more information.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public
22 License along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
24
25 Copyright (c) 2004 Bruno T. C. de Oliveira
26 */
27
28
29 #ifndef btco_ROTE_rote_h
30 #define btco_ROTE_rote_h
31
32 #ifdef USE_NCURSES
33 #include <ncurses.h>
34 #else
35 #include <stdbool.h>
36 #endif
37 #include <sys/types.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40
41 /* Color codes: 0 = black, 1 = red, 2 = green, 3 = yellow, 4 = blue,
42  *              5 = magenta, 6 = cyan, 7 = white. 
43  *
44  * An 'attribute' as used in this library means an 8-bit value that conveys
45  * a foreground color code, a background color code, and the bold
46  * and blink bits. Each cell in the virtual terminal screen is associated
47  * with an attribute that specifies its appearance. The bits of an attribute,
48  * from most significant to least significant, are 
49  *
50  *  bit:      7 6 5 4 3 2 1 0
51  *  content:  S F F F H B B B
52  *            | `-,-' | `-,-'
53  *            |   |   |   |
54  *            |   |   |   `----- 3-bit background color code (0 - 7)
55  *            |   |   `--------- blink bit (if on, text is blinking)
56  *            |   `------------- 3-bit foreground color code (0 - 7)
57  *            `----------------- bold bit
58  *
59  * It is however recommended that you use the provided macros rather
60  * than dealing with this format directly.
61  *
62  * Sometimes we will call the 'SFFF' nibble above the 'extended
63  * foreground color code', and the 'HBBB' nibble the 'extended background
64  * color code'. So the extended color codes are just the regular
65  * color codes except that they have an additional bit (the most significant
66  * bit) indicating bold/blink.
67  */
68
69 /* retrieve attribute fields */
70 #define ROTE_ATTR_BG(attr)              ((attr) & 0x07)
71 #define ROTE_ATTR_FG(attr)              (((attr) & 0x70) >> 4)
72
73 /* retrieve 'extended' color codes (see above for info) */
74 #define ROTE_ATTR_XBG(attr)             ((attr) & 0x0F)
75 #define ROTE_ATTR_XFG(attr)             (((attr) & 0xF0) >> 4)
76
77 /* set attribute fields. This requires attr to be an lvalue, and it will
78  * be evaluated more than once. Use with care. */
79 #define ROTE_ATTR_MOD_BG(attr, newbg)    attr &= 0xF8, attr |= (newbg)
80 #define ROTE_ATTR_MOD_FG(attr, newfg)    attr &= 0x8F, attr |= ((newfg) << 4)
81 #define ROTE_ATTR_MOD_XBG(attr, newxbg)  attr &= 0xF0, attr |= (newxbg)
82 #define ROTE_ATTR_MOD_XFG(attr, newxfg)  attr &= 0x0F, attr |= ((newxfg) << 4)
83 #define ROTE_ATTR_MOD_BOLD(attr, boldbit) \
84                                attr &= 0x7F, attr |= (boldbit)?0x80:0x00
85 #define ROTE_ATTR_MOD_BLINK(attr, blinkbit) \
86                                attr &= 0xF7, attr |= (blinkbit)?0x08:0x00
87
88 /* these return non-zero for 'yes', zero for 'no'. Don't rely on them being 
89  * any more specific than that (e.g. being exactly 1 for 'yes' or whatever). */
90 #define ROTE_ATTR_BOLD(attr)            ((attr) & 0x80)
91 #define ROTE_ATTR_BLINK(attr)           ((attr) & 0x08)
92
93 /* Represents each of the text cells in the terminal screen */
94 typedef struct RoteCell_ {
95    unsigned char ch;    /* >= 32, that is, control characters are not
96                          * allowed to be on the virtual screen */
97
98    unsigned char attr;  /* a color attribute, as described previously */
99 } RoteCell;
100
101 /* Declaration of opaque rote_Term_Private structure */
102 typedef struct RoteTermPrivate_ RoteTermPrivate;
103
104 /* Represents a virtual terminal. You may directly access the fields
105  * of this structure, but please pay close attention to the fields
106  * marked read-only or with special usage notes. */
107 typedef struct RoteTerm_ {
108    int rows, cols;              /* terminal dimensions, READ-ONLY. You
109                                  * can't resize the terminal by changing
110                                  * this (a segfault is about all you will 
111                                  * accomplish). */
112
113    RoteCell **cells;            /* matrix of cells. This
114                                  * matrix is indexed as cell[row][column]
115                                  * where 0 <= row < rows and
116                                  *       0 <= col < cols
117                                  *
118                                  * You may freely modify the contents of
119                                  * the cells.
120                                  */
121
122    int crow, ccol;              /* cursor coordinates. READ-ONLY. */
123
124    unsigned char curattr;       /* current attribute, that is the attribute
125                                  * that will be used for newly inserted
126                                  * characters */
127
128    pid_t childpid;              /* pid of the child process running in the
129                                  * terminal; 0 for none. This is READ-ONLY. */
130
131    RoteTermPrivate *pd;         /* private state data */
132
133    bool insert;                 /* insert or replace mode */
134    /* --- dirtiness flags: the following flags will be raised when the
135     * corresponding items are modified. They can only be unset by YOU
136     * (when, for example, you redraw the term or something) --- */
137    bool curpos_dirty;           /* whether cursor location has changed */
138    bool *line_dirty;            /* whether each row is dirty  */
139    /* --- end dirtiness flags */
140 } RoteTerm;
141
142 /* Creates a new virtual terminal with the given dimensions. You
143  * must destroy it with rote_vt_destroy after you are done with it.
144  * The terminal will be initially blank and the cursor will
145  * be at the top-left corner. 
146  *
147  * Returns NULL on error.
148  */
149 RoteTerm *rote_vt_create(int rows, int cols);
150
151 /* Destroys a virtual terminal previously created with
152  * rote_vt_create. If rt == NULL, does nothing. */
153 void rote_vt_destroy(RoteTerm *rt);
154
155 /* Starts a forked process in the terminal. The <command> parameter
156  * is a shell command to execute (it will be interpreted by '/bin/sh -c') 
157  * Returns the pid of the forked process. 
158  *
159  * Some useful reminders: If you want to be notified when child processes exit,
160  * you should handle the SIGCHLD signal.  If, on the other hand, you want to
161  * ignore exitting child processes, you should set the SIGCHLD handler to
162  * SIG_IGN to prevent child processes from hanging around the system as 'zombie
163  * processes'. 
164  *
165  * Continuing to write to a RoteTerm whose child process has died does not
166  * accomplish a lot, but is not an error and should not cause your program
167  * to crash or block indefinitely or anything of that sort :-)
168  * If, however, you want to be tidy and inform the RoteTerm that its
169  * child has died, call rote_vt_forsake_child when appropriate.
170  *
171  * If there is an error, returns -1. Notice that passing an invalid
172  * command will not cause an error at this level: the shell will try
173  * to execute the command and will exit with status 127. You can catch
174  * that by installing a SIGCHLD handler if you want.
175  */
176 pid_t rote_vt_forkpty(RoteTerm *rt, const char *command);
177
178 /* Disconnects the RoteTerm from its forked child process. This function
179  * should be called when the child process dies or something of the sort.
180  * It is not strictly necessary to call this function, but it is
181  * certainly tidy. */
182 void rote_vt_forsake_child(RoteTerm *rt);
183
184 /* Does some data plumbing, that is, sees if the sub process has
185  * something to write to the terminal, and if so, write it. If you
186  * called rote_vt_fork to start a forked process, you must call
187  * this function regularly to update the terminal. 
188  *
189  * This function will not block, that is, if there is no data to be
190  * read from the child process it will return immediately. */
191 void rote_vt_update(RoteTerm *rt);
192
193 /* Puts data into the terminal: if there is a forked process running,
194  * the data will be sent to it. If there is no forked process,
195  * the data will simply be injected into the terminal (as in
196  * rote_vt_inject) */
197 void rote_vt_write(RoteTerm *rt, const char *data, int length);
198
199 /* Inject data into the terminal. <data> needs NOT be 0-terminated:
200  * its length is solely determined by the <length> parameter. Please
201  * notice that this writes directly to the terminal, that is,
202  * this function does NOT send the data to the forked process
203  * running in the terminal (if any). For that, you might want
204  * to use rote_vt_write.
205  */
206 void rote_vt_inject(RoteTerm *rt, const char *data, int length);
207
208 #ifdef USE_NCURSES
209 /* Paints the virtual terminal screen on the given window, putting
210  * the top-left corner at the given position. The cur_set_attr
211  * function must set the curses attributes given a Rote attribute
212  * byte. It should, for example, do wattrset(win, COLOR_PAIR(n)) where
213  * n is the colorpair appropriate for the attribute and such.
214  *
215  * If you pass NULL for cur_set_attr, the default implementation will
216  * set the color pair given by (bg * 8 + 7 - fg), which seems to be
217  * a common mapping, and the bold and blink attributes will be mapped 
218  * to A_BOLD and A_BLINK.
219  *
220  * At the end of the function, the cursor will be left where the virtual 
221  * cursor of the terminal is supposed to be.
222  *
223  * This function does not call wrefresh(win); you have to do that yourself.
224  * This function automatically calls rote_vt_update prior to drawing
225  * so that the drawn contents are accurate.
226  */
227 void rote_vt_draw(RoteTerm *rt, WINDOW *win, int startrow, int startcol,
228                   void (*cur_set_attr)(WINDOW *win, unsigned char attr));
229
230 #endif
231 /* Indicates to the terminal that the given key has been pressed.
232  * This will cause the terminal to rote_vt_write() the appropriate
233  * escape sequence for that key (that is, the escape sequence
234  * that the linux text-mode console would produce for it). The argument,
235  * keycode, must be a CURSES EXTENDED KEYCODE, the ones you get
236  * when you use keypad(somewin, TRUE) (see man page). */
237 void rote_vt_keypress(RoteTerm *rt, int keycode);
238
239 /* Takes a snapshot of the current contents of the terminal and
240  * saves them to a dynamically allocated buffer. Returns a pointer
241  * to the newly created buffer, which you can pass to
242  * rote_vt_restore_snapshot. Caller is responsible for free()'ing when
243  * the snapshot is no longer needed. */
244 void *rote_vt_take_snapshot(RoteTerm *rt);
245
246 /* Restores a snapshot previously taken with rote_vt_take_snapshot.
247  * This function does NOT free() the passed buffer */
248 void rote_vt_restore_snapshot(RoteTerm *rt, void *snapbuf);
249
250 /* Returns the pseudo tty descriptor associated with the given terminal.
251  * Please don't do weird things with it (like close it for instance),
252  * or things will break 
253  * 
254  * This function returns -1 if the given terminal does not yet have
255  * an associated pty. A pty is only associated to a terminal when
256  * needed, e.g. on a call to rote_vt_forkpty. */
257 int rote_vt_get_pty_fd(RoteTerm *rt);
258
259 /* Declaration of custom escape sequence callback type. See the
260  * rote_vt_add_es_handler function for more info */
261 typedef int (*rote_es_handler_t)(RoteTerm *rt, const char *es);
262
263 /* Installs a custom escape sequence handler for the given RoteTerm.
264  * The handler will be called by the library every time it tries to
265  * recognize an escape sequence; depending on the return value of the
266  * handler, it will proceed in a different manner. See the description
267  * of the possible return values (ROTE_HANDLERESULT_* constants) below
268  * for more info.
269  *
270  * This handler will be called EACH TIME THE ESCAPE SEQUENCE BUFFER
271  * RECEIVES A CHARACTER. Therefore, it must execute speedily in order
272  * not to create too heavy a performance penalty. In particular, the
273  * writer of the handler should take care to quickly test for invalid
274  * or incomplete escape sequences before trying to do more elaborate
275  * parsing.
276  *
277  * The handler will NOT be called with an empty escape sequence (i.e.
278  * one in which only the initial ESC was received).
279  *
280  * The custom handler receives the terminal it pertains to and the
281  * escape sequence as a string (without the initial escape character).
282  *
283  * The handler may of course modify the terminal as it sees fit, taking 
284  * care not to corrupt it of course (in particular, it should appropriately 
285  * raise the line_dirty[] and curpos_dirty flags to indicate what it has 
286  * changed).
287  */
288 void rote_vt_install_handler(RoteTerm *rt, rote_es_handler_t handler);
289                             
290 /* Possible return values for the custom handler function and their
291  * meanings: */
292 #define ROTE_HANDLERESULT_OK 0      /* means escape sequence was handled */
293
294 #define ROTE_HANDLERESULT_NOTYET 1  /* means the escape sequence was not
295                                      * recognized yet, but there is hope that
296                                      * it still will once more characters
297                                      * arrive (i.e. it is not yet complete).
298                                      *
299                                      * The library will thus continue collecting
300                                      * characters and calling the handler as
301                                      * each character arrives until
302                                      * either OK or NOWAY is returned.
303                                      */
304
305 #define ROTE_HANDLERESULT_NOWAY 2   /* means the escape sequence was not
306                                      * recognized, and there is no chance
307                                      * that it will even if more characters
308                                      * are added to it. */
309
310 #endif
311