Merge Irssi 0.8.16-rc1
[silc.git] / apps / irssi / src / fe-text / terminfo-core.c
1 #include "module.h"
2 #include "signals.h"
3 #include "terminfo-core.h"
4
5 #ifndef _POSIX_VDISABLE
6 #  define _POSIX_VDISABLE 0
7 #endif
8
9 #define tput(s) tputs(s, 0, term_putchar)
10 inline static int term_putchar(int c)
11 {
12         return fputc(c, current_term->out);
13 }
14
15 /* Don't bother including curses.h because of these -
16    they might not even be defined there */
17 char *tparm();
18 int tputs();
19
20 #ifdef HAVE_TERMINFO
21 int setupterm();
22 char *tigetstr();
23 int tigetnum();
24 int tigetflag();
25 #define term_getstr(x, buffer) tigetstr(x.ti_name)
26 #define term_getnum(x) tigetnum(x.ti_name);
27 #define term_getflag(x) tigetflag(x.ti_name);
28 #else
29 int tgetent();
30 char *tgetstr();
31 int tgetnum();
32 int tgetflag();
33 #define term_getstr(x, buffer) tgetstr(x.tc_name, &buffer)
34 #define term_getnum(x) tgetnum(x.tc_name)
35 #define term_getflag(x) tgetflag(x.tc_name)
36 #endif
37
38 #define CAP_TYPE_FLAG   0
39 #define CAP_TYPE_INT    1
40 #define CAP_TYPE_STR    2
41
42 typedef struct {
43         const char *ti_name; /* terminfo name */
44         const char *tc_name; /* termcap name */
45         int type;
46         unsigned int offset;
47 } TERMINFO_REC;
48
49 TERM_REC *current_term;
50
51 /* Define only what we might need */
52 static TERMINFO_REC tcaps[] = {
53         /* Terminal size */
54         { "cols",       "co",   CAP_TYPE_INT,   G_STRUCT_OFFSET(TERM_REC, width) },
55         { "lines",      "li",   CAP_TYPE_INT,   G_STRUCT_OFFSET(TERM_REC, height) },
56
57         /* Cursor movement */
58         { "smcup",      "ti",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_smcup) },
59         { "rmcup",      "te",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_rmcup) },
60         { "cup",        "cm",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_cup) },
61         { "hpa",        "ch",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_hpa) },
62         { "vpa",        "vh",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_vpa) },
63         { "cub1",       "le",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_cub1) },
64         { "cuf1",       "nd",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_cuf1) },
65         { "civis",      "vi",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_civis) },
66         { "cnorm",      "ve",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_cnorm) },
67
68         /* Scrolling */
69         { "csr",        "cs",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_csr) },
70         { "wind",       "wi",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_wind) },
71         { "ri",         "sr",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_ri) },
72         { "rin",        "SR",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_rin) },
73         { "ind",        "sf",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_ind) },
74         { "indn",       "SF",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_indn) },
75         { "il",         "AL",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_il) },
76         { "il1",        "al",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_il1) },
77         { "dl",         "DL",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_dl) },
78         { "dl1",        "dl",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_dl1) },
79
80         /* Clearing screen */
81         { "clear",      "cl",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_clear) },
82         { "ed",         "cd",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_ed) },
83
84         /* Clearing to end of line */
85         { "el",         "ce",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_el) },
86
87         /* Repeating character */
88         { "rep",        "rp",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_rep) },
89
90         /* Colors */
91         { "colors",     "Co",   CAP_TYPE_INT,   G_STRUCT_OFFSET(TERM_REC, TI_colors) },
92         { "sgr0",       "me",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_sgr0) },
93         { "smul",       "us",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_smul) },
94         { "rmul",       "ue",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_rmul) },
95         { "smso",       "so",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_smso) },
96         { "rmso",       "se",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_rmso) },
97         { "bold",       "md",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_bold) },
98         { "blink",      "mb",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_blink) },
99         { "setaf",      "AF",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_setaf) },
100         { "setab",      "AB",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_setab) },
101         { "setf",       "Sf",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_setf) },
102         { "setb",       "Sb",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_setb) },
103
104         /* Beep */
105         { "bel",        "bl",   CAP_TYPE_STR,   G_STRUCT_OFFSET(TERM_REC, TI_bel) },
106 };
107
108 /* Move cursor (cursor_address / cup) */
109 static void _move_cup(TERM_REC *term, int x, int y)
110 {
111         tput(tparm(term->TI_cup, y, x));
112 }
113
114 /* Move cursor (column_address+row_address / hpa+vpa) */
115 static void _move_pa(TERM_REC *term, int x, int y)
116 {
117         tput(tparm(term->TI_hpa, x));
118         tput(tparm(term->TI_vpa, y));
119 }
120
121 /* Move cursor from a known position */
122 static void _move_relative(TERM_REC *term, int oldx, int oldy, int x, int y)
123 {
124         if (oldx == 0 && x == 0 && y == oldy+1) {
125                 /* move to beginning of next line -
126                    hope this works everywhere */
127                 tput("\r\n");
128                 return;
129         }
130
131         if (oldx > 0 && y == oldy) {
132                 /* move cursor left/right */
133                 if (x == oldx-1 && term->TI_cub1) {
134                         tput(tparm(term->TI_cub1));
135                         return;
136                 }
137                 if (x == oldx+1 && y == oldy && term->TI_cuf1) {
138                         tput(tparm(term->TI_cuf1));
139                         return;
140                 }
141         }
142
143         /* fallback to absolute positioning */
144         if (term->TI_cup) {
145                 tput(tparm(term->TI_cup, y, x));
146                 return;
147         }
148
149         if (oldy != y)
150                 tput(tparm(term->TI_vpa, y));
151         if (oldx != x)
152                 tput(tparm(term->TI_hpa, x));
153 }
154
155 /* Set cursor visible/invisible */
156 static void _set_cursor_visible(TERM_REC *term, int set)
157 {
158         tput(tparm(set ? term->TI_cnorm : term->TI_civis));
159 }
160
161 #define scroll_region_setup(term, y1, y2) \
162         if ((term)->TI_csr != NULL) \
163                 tput(tparm((term)->TI_csr, y1, y2)); \
164         else if ((term)->TI_wind != NULL) \
165                 tput(tparm((term)->TI_wind, y1, y2, 0, (term)->width-1));
166
167 /* Scroll (change_scroll_region+parm_rindex+parm_index / csr+rin+indn) */
168 static void _scroll_region(TERM_REC *term, int y1, int y2, int count)
169 {
170         /* setup the scrolling region to wanted area */
171         scroll_region_setup(term, y1, y2);
172
173         term->move(term, 0, y1);
174         if (count > 0) {
175                 term->move(term, 0, y2);
176                 tput(tparm(term->TI_indn, count, count));
177         } else if (count < 0) {
178                 term->move(term, 0, y1);
179                 tput(tparm(term->TI_rin, -count, -count));
180         }
181
182         /* reset the scrolling region to full screen */
183         scroll_region_setup(term, 0, term->height-1);
184 }
185
186 /* Scroll (change_scroll_region+scroll_reverse+scroll_forward / csr+ri+ind) */
187 static void _scroll_region_1(TERM_REC *term, int y1, int y2, int count)
188 {
189         int i;
190
191         /* setup the scrolling region to wanted area */
192         scroll_region_setup(term, y1, y2);
193
194         if (count > 0) {
195                 term->move(term, 0, y2);
196                 for (i = 0; i < count; i++)
197                         tput(tparm(term->TI_ind));
198         } else if (count < 0) {
199                 term->move(term, 0, y1);
200                 for (i = count; i < 0; i++)
201                         tput(tparm(term->TI_ri));
202         }
203
204         /* reset the scrolling region to full screen */
205         scroll_region_setup(term, 0, term->height-1);
206 }
207
208 /* Scroll (parm_insert_line+parm_delete_line / il+dl) */
209 static void _scroll_line(TERM_REC *term, int y1, int y2, int count)
210 {
211         /* setup the scrolling region to wanted area -
212            this might not necessarily work with il/dl, but at least it
213            looks better if it does */
214         scroll_region_setup(term, y1, y2);
215
216         if (count > 0) {
217                 term->move(term, 0, y1);
218                 tput(tparm(term->TI_dl, count, count));
219                 term->move(term, 0, y2-count+1);
220                 tput(tparm(term->TI_il, count, count));
221         } else if (count < 0) {
222                 term->move(term, 0, y2+count+1);
223                 tput(tparm(term->TI_dl, -count, -count));
224                 term->move(term, 0, y1);
225                 tput(tparm(term->TI_il, -count, -count));
226         }
227
228         /* reset the scrolling region to full screen */
229         scroll_region_setup(term, 0, term->height-1);
230 }
231
232 /* Scroll (insert_line+delete_line / il1+dl1) */
233 static void _scroll_line_1(TERM_REC *term, int y1, int y2, int count)
234 {
235         int i;
236
237         if (count > 0) {
238                 term->move(term, 0, y1);
239                 for (i = 0; i < count; i++)
240                         tput(tparm(term->TI_dl1));
241                 term->move(term, 0, y2-count+1);
242                 for (i = 0; i < count; i++)
243                         tput(tparm(term->TI_il1));
244         } else if (count < 0) {
245                 term->move(term, 0, y2+count+1);
246                 for (i = count; i < 0; i++)
247                         tput(tparm(term->TI_dl1));
248                 term->move(term, 0, y1);
249                 for (i = count; i < 0; i++)
250                         tput(tparm(term->TI_il1));
251         }
252 }
253
254 /* Clear screen (clear_screen / clear) */
255 static void _clear_screen(TERM_REC *term)
256 {
257         tput(tparm(term->TI_clear));
258 }
259
260 /* Clear screen (clr_eos / ed) */
261 static void _clear_eos(TERM_REC *term)
262 {
263         term->move(term, 0, 0);
264         tput(tparm(term->TI_ed));
265 }
266
267 /* Clear screen (parm_delete_line / dl) */
268 static void _clear_del(TERM_REC *term)
269 {
270         term->move(term, 0, 0);
271         tput(tparm(term->TI_dl, term->height, term->height));
272 }
273
274 /* Clear screen (delete_line / dl1) */
275 static void _clear_del_1(TERM_REC *term)
276 {
277         int i;
278
279         term->move(term, 0, 0);
280         for (i = 0; i < term->height; i++)
281                 tput(tparm(term->TI_dl1));
282 }
283
284 /* Clear to end of line (clr_eol / el) */
285 static void _clrtoeol(TERM_REC *term)
286 {
287         tput(tparm(term->TI_el));
288 }
289
290 /* Repeat character (rep / rp) */
291 static void _repeat(TERM_REC *term, char chr, int count)
292 {
293         tput(tparm(term->TI_rep, chr, count));
294 }
295
296 /* Repeat character (manual) */
297 static void _repeat_manual(TERM_REC *term, char chr, int count)
298 {
299         while (count > 0) {
300                 putc(chr, term->out);
301                 count--;
302         }
303 }
304
305 /* Reset all terminal attributes */
306 static void _set_normal(TERM_REC *term)
307 {
308         tput(tparm(term->TI_normal));
309 }
310
311 static void _set_blink(TERM_REC *term)
312 {
313         tput(tparm(term->TI_blink));
314 }
315
316 /* Bold on */
317 static void _set_bold(TERM_REC *term)
318 {
319         tput(tparm(term->TI_bold));
320 }
321
322 /* Underline on/off */
323 static void _set_uline(TERM_REC *term, int set)
324 {
325         tput(tparm(set ? term->TI_smul : term->TI_rmul));
326 }
327
328 /* Standout on/off */
329 static void _set_standout(TERM_REC *term, int set)
330 {
331         tput(tparm(set ? term->TI_smso : term->TI_rmso));
332 }
333
334 /* Change foreground color */
335 static void _set_fg(TERM_REC *term, int color)
336 {
337         tput(tparm(term->TI_fg[color % term->TI_colors]));
338 }
339
340 /* Change background color */
341 static void _set_bg(TERM_REC *term, int color)
342 {
343         tput(tparm(term->TI_bg[color % term->TI_colors]));
344 }
345
346 /* Beep */
347 static void _beep(TERM_REC *term)
348 {
349         tput(tparm(term->TI_bel));
350 }
351
352 static void _ignore(TERM_REC *term)
353 {
354 }
355
356 static void _ignore_parm(TERM_REC *term, int param)
357 {
358 }
359
360 static void term_fill_capabilities(TERM_REC *term)
361 {
362         int i, ival;
363         char *sval;
364         void *ptr;
365
366 #ifndef HAVE_TERMINFO
367         char *tptr = term->buffer2;
368 #endif
369         for (i = 0; i < sizeof(tcaps)/sizeof(tcaps[0]); i++) {
370                 ptr = G_STRUCT_MEMBER_P(term, tcaps[i].offset);
371
372                 switch (tcaps[i].type) {
373                 case CAP_TYPE_FLAG:
374                         ival = term_getflag(tcaps[i]);
375                         *(int *)ptr = ival;
376                         break;
377                 case CAP_TYPE_INT:
378                         ival = term_getnum(tcaps[i]);
379                         *(int *)ptr = ival;
380                         break;
381                 case CAP_TYPE_STR:
382                         sval = term_getstr(tcaps[i], tptr);
383                         if (sval == (char *) -1)
384                                 *(char **)ptr = NULL;
385                         else
386                                 *(char **)ptr = sval;
387                         break;
388                 }
389         }
390 }
391
392 static void terminfo_colors_deinit(TERM_REC *term)
393 {
394         int i;
395
396         if (terminfo_is_colors_set(term)) {
397                 for (i = 0; i < term->TI_colors; i++) {
398                         g_free(term->TI_fg[i]);
399                         g_free(term->TI_bg[i]);
400                 }
401
402                 g_free_and_null(term->TI_fg);
403                 g_free_and_null(term->TI_bg);
404         }
405 }
406
407 /* Setup colors - if force is set, use ANSI-style colors if
408    terminal capabilities don't contain color codes */
409 void terminfo_setup_colors(TERM_REC *term, int force)
410 {
411         static const char ansitab[16] = {
412                 0, 4, 2, 6, 1, 5, 3, 7,
413                 8, 12, 10, 14, 9, 13, 11, 15
414         };
415         unsigned int i, color;
416
417         terminfo_colors_deinit(term);
418
419         if (force && term->TI_setf == NULL && term->TI_setaf == NULL)
420                 term->TI_colors = 8;
421
422         if ((term->TI_setf || term->TI_setaf || force) &&
423              term->TI_colors > 0) {
424                 term->TI_fg = g_new0(char *, term->TI_colors);
425                 term->TI_bg = g_new0(char *, term->TI_colors);
426                 term->set_fg = _set_fg;
427                 term->set_bg = _set_bg;
428         } else {
429                 /* no colors */
430                 term->TI_colors = 0;
431                 term->set_fg = term->set_bg = _ignore_parm;
432         }
433
434         if (term->TI_setaf) {
435                 for (i = 0; i < term->TI_colors; i++) {
436                         color = i < 16 ? ansitab[i] : i;
437                         term->TI_fg[i] = g_strdup(tparm(term->TI_setaf, color, 0));
438                 }
439         } else if (term->TI_setf) {
440                 for (i = 0; i < term->TI_colors; i++)
441                         term->TI_fg[i] = g_strdup(tparm(term->TI_setf, i, 0));
442         } else if (force) {
443                 for (i = 0; i < 8; i++)
444                         term->TI_fg[i] = g_strdup_printf("\033[%dm", 30+ansitab[i]);
445         }
446
447         if (term->TI_setab) {
448                 for (i = 0; i < term->TI_colors; i++) {
449                         color = i < 16 ? ansitab[i] : i;
450                         term->TI_bg[i] = g_strdup(tparm(term->TI_setab, color, 0));
451                 }
452         } else if (term->TI_setb) {
453                 for (i = 0; i < term->TI_colors; i++)
454                         term->TI_bg[i] = g_strdup(tparm(term->TI_setb, i, 0));
455         } else if (force) {
456                 for (i = 0; i < 8; i++)
457                         term->TI_bg[i] = g_strdup_printf("\033[%dm", 40+ansitab[i]);
458         }
459 }
460
461 static void terminfo_input_init(TERM_REC *term)
462 {
463         tcgetattr(fileno(term->in), &term->old_tio);
464         memcpy(&term->tio, &term->old_tio, sizeof(term->tio));
465
466         term->tio.c_lflag &= ~(ICANON | ECHO); /* CBREAK, no ECHO */
467         term->tio.c_cc[VMIN] = 1; /* read() is satisfied after 1 char */
468         term->tio.c_cc[VTIME] = 0; /* No timer */
469
470         /* Disable INTR, QUIT, VDSUSP and SUSP keys */
471         term->tio.c_cc[VINTR] = _POSIX_VDISABLE;
472         term->tio.c_cc[VQUIT] = _POSIX_VDISABLE;
473 #ifdef VDSUSP
474         term->tio.c_cc[VDSUSP] = _POSIX_VDISABLE;
475 #endif
476 #ifdef VSUSP
477         term->tio.c_cc[VSUSP] = _POSIX_VDISABLE;
478 #endif
479
480         tcsetattr(fileno(term->in), TCSADRAIN, &term->tio);
481
482 }
483
484 static void terminfo_input_deinit(TERM_REC *term)
485 {
486         tcsetattr(fileno(term->in), TCSADRAIN, &term->old_tio);
487 }
488
489 void terminfo_cont(TERM_REC *term)
490 {
491         if (term->TI_smcup)
492                 tput(tparm(term->TI_smcup));
493         terminfo_input_init(term);
494 }
495
496 void terminfo_stop(TERM_REC *term)
497 {
498         /* reset colors */
499         terminfo_set_normal();
500         /* move cursor to bottom of the screen */
501         terminfo_move(0, term->height-1);
502
503         /* stop cup-mode */
504         if (term->TI_rmcup)
505                 tput(tparm(term->TI_rmcup));
506
507         /* reset input settings */
508         terminfo_input_deinit(term);
509         fflush(term->out);
510 }
511
512 static int term_setup(TERM_REC *term)
513 {
514         GString *str;
515 #ifdef HAVE_TERMINFO
516         int err;
517 #endif
518         char *term_env;
519
520         term_env = getenv("TERM");
521         if (term_env == NULL) {
522                 fprintf(stderr, "TERM environment not set\n");
523                 return 0;
524         }
525
526 #ifdef HAVE_TERMINFO
527         if (setupterm(term_env, 1, &err) != 0) {
528                 fprintf(stderr, "setupterm() failed for TERM=%s: %d\n", term_env, err);
529                 return 0;
530         }
531 #else
532         if (tgetent(term->buffer1, term_env) < 1)
533         {
534                 fprintf(stderr, "Termcap not found for TERM=%s\n", term_env);
535                 return 0;
536         }
537 #endif
538
539         term_fill_capabilities(term);
540
541         /* Cursor movement */
542         if (term->TI_cup)
543                 term->move = _move_cup;
544         else if (term->TI_hpa && term->TI_vpa)
545                 term->move = _move_pa;
546         else {
547                 fprintf(stderr, "Terminal doesn't support cursor movement\n");
548                 return 0;
549         }
550         term->move_relative = _move_relative;
551         term->set_cursor_visible = term->TI_civis && term->TI_cnorm ?
552                 _set_cursor_visible : _ignore_parm;
553
554         /* Scrolling */
555         if ((term->TI_csr || term->TI_wind) && term->TI_rin && term->TI_indn)
556                 term->scroll = _scroll_region;
557         else if (term->TI_il && term->TI_dl)
558                 term->scroll = _scroll_line;
559         else if ((term->TI_csr || term->TI_wind) && term->TI_ri && term->TI_ind)
560                 term->scroll = _scroll_region_1;
561         else if (term->scroll == NULL && (term->TI_il1 && term->TI_dl1))
562                 term->scroll = _scroll_line_1;
563         else if (term->scroll == NULL) {
564                 fprintf(stderr, "Terminal doesn't support scrolling\n");
565                 return 0;
566         }
567
568         /* Clearing screen */
569         if (term->TI_clear)
570                 term->clear = _clear_screen;
571         else if (term->TI_ed)
572                 term->clear = _clear_eos;
573         else if (term->TI_dl)
574                 term->clear = _clear_del;
575         else if (term->TI_dl1)
576                 term->clear = _clear_del_1;
577         else {
578                 /* we could do this by line inserts as well, but don't
579                    bother - if some terminal has insert line it most probably
580                    has delete line as well, if not a regular clear screen */
581                 fprintf(stderr, "Terminal doesn't support clearing screen\n");
582                 return 0;
583         }
584
585         /* Clearing to end of line */
586         if (term->TI_el)
587                 term->clrtoeol = _clrtoeol;
588         else {
589                 fprintf(stderr, "Terminal doesn't support clearing to end of line\n");
590                 return 0;
591         }
592
593         /* Repeating character */
594         if (term->TI_rep)
595                 term->repeat = _repeat;
596         else
597                 term->repeat = _repeat_manual;
598
599         /* Bold, underline, standout */
600         term->set_blink = term->TI_blink ? _set_blink : _ignore;
601         term->set_bold = term->TI_bold ? _set_bold : _ignore;
602         term->set_uline = term->TI_smul && term->TI_rmul ?
603                 _set_uline : _ignore_parm;
604         term->set_standout = term->TI_smso && term->TI_rmso ?
605                 _set_standout : _ignore_parm;
606
607         /* Create a string to set all attributes off */
608         str = g_string_new(NULL);
609         if (term->TI_sgr0)
610                 g_string_append(str, term->TI_sgr0);
611         if (term->TI_rmul && (term->TI_sgr0 == NULL || strcmp(term->TI_rmul, term->TI_sgr0) != 0))
612                 g_string_append(str, term->TI_rmul);
613         if (term->TI_rmso && (term->TI_sgr0 == NULL || strcmp(term->TI_rmso, term->TI_sgr0) != 0))
614                 g_string_append(str, term->TI_rmso);
615         term->TI_normal = str->str;
616         g_string_free(str, FALSE);
617         term->set_normal = _set_normal;
618
619         term->beep = term->TI_bel ? _beep : _ignore;
620
621         terminfo_setup_colors(term, FALSE);
622         terminfo_cont(term);
623         return 1;
624 }
625
626 TERM_REC *terminfo_core_init(FILE *in, FILE *out)
627 {
628         TERM_REC *old_term, *term;
629
630         old_term = current_term;
631         current_term = term = g_new0(TERM_REC, 1);
632
633         term->in = in;
634         term->out = out;
635
636         if (!term_setup(term)) {
637                 g_free(term);
638                 term = NULL;
639         }
640
641         current_term = old_term;
642         return term;
643 }
644
645 void terminfo_core_deinit(TERM_REC *term)
646 {
647         TERM_REC *old_term;
648
649         old_term = current_term;
650         current_term = term;
651         term->set_normal(term);
652         current_term = old_term;
653
654         terminfo_stop(term);
655
656         g_free(term->TI_normal);
657         terminfo_colors_deinit(term);
658
659         g_free(term);
660 }