1 /* TN5250
2 * Copyright (C) 1997-2008 Michael Madore
3 *
4 * This file is part of TN5250.
5 *
6 * TN5250 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1, or (at your option)
9 * any later version.
10 *
11 * TN5250 is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this software; see the file COPYING. If not, write to
18 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307 USA
20 *
21 */
22 #define _TN5250_TERMINAL_PRIVATE_DEFINED
23 #include "tn5250-private.h"
24 #include "cursesterm.h"
25
26 #ifdef USE_CURSES
27
28 /* Some versions of ncurses don't have this defined. */
29 #ifndef A_VERTICAL
30 #define A_VERTICAL ((1UL) << ((22) + 8))
31 #endif /* A_VERTICAL */
32
33 /* Some older versions of ncurses don't define NCURSES_COLOR_T */
34 #ifndef NCURSES_COLOR_T
35 #define NCURSES_COLOR_T short
36 #endif
37
38 /* Mapping of 5250 colors to curses colors */
39 struct _curses_color_map {
40 char *name;
41 NCURSES_COLOR_T ref;
42 attr_t bld;
43 };
44 typedef struct _curses_color_map curses_color_map;
45
46 static curses_color_map colorlist[] =
47 {
48 { "black", COLOR_BLACK },
49 { "red", COLOR_RED, A_BOLD },
50 { "green", COLOR_GREEN },
51 { "yellow", COLOR_YELLOW,A_BOLD },
52 { "blue", COLOR_CYAN, A_BOLD },
53 { "pink", COLOR_MAGENTA },
54 { "turquoise", COLOR_CYAN },
55 { "white", COLOR_WHITE, A_BOLD },
56 { NULL, -1 }
57 };
58
59 #define A_5250_GREEN ((attr_t)COLOR_PAIR(COLOR_GREEN)|colorlist[COLOR_GREEN].bld)
60 #define A_5250_WHITE ((attr_t)COLOR_PAIR(COLOR_WHITE)|colorlist[COLOR_WHITE].bld)
61 #define A_5250_RED ((attr_t)COLOR_PAIR(COLOR_RED)|colorlist[COLOR_RED].bld)
62 #define A_5250_TURQ ((attr_t)COLOR_PAIR(COLOR_CYAN)|colorlist[COLOR_CYAN].bld)
63 #define A_5250_YELLOW ((attr_t)COLOR_PAIR(COLOR_YELLOW)|colorlist[COLOR_YELLOW].bld)
64 #define A_5250_PINK ((attr_t)COLOR_PAIR(COLOR_MAGENTA)|colorlist[COLOR_MAGENTA].bld)
65 #define A_5250_BLUE ((attr_t)COLOR_PAIR(COLOR_BLUE)|colorlist[COLOR_BLUE].bld)
66
67 /*@-globstate -nullpass@*/ /* lclint incorrectly assumes stdscr may be NULL */
68
69 static attr_t attribute_map[33];
70
71 static void curses_terminal_init(Tn5250Terminal * This) /*@modifies This@*/;
72 static void curses_terminal_term(Tn5250Terminal * This) /*@modifies This@*/;
73 static void curses_terminal_destroy(Tn5250Terminal /*@only@*/ * This);
74 static int curses_terminal_width(Tn5250Terminal * This);
75 static int curses_terminal_height(Tn5250Terminal * This);
76 static int curses_terminal_flags(Tn5250Terminal * This);
77 static void curses_terminal_update(Tn5250Terminal * This,
78 Tn5250Display * display) /*@modifies This@*/;
79 static void curses_terminal_update_indicators(Tn5250Terminal * This,
80 Tn5250Display * display) /*@modifies This@*/;
81 static int curses_terminal_waitevent(Tn5250Terminal * This) /*@modifies This@*/;
82 static int curses_terminal_getkey(Tn5250Terminal * This) /*@modifies This@*/;
83 static int curses_terminal_get_esc_key(Tn5250Terminal * This, int is_esc) /*@modifies This@*/;
84 static void curses_terminal_beep(Tn5250Terminal * This);
85 static int curses_terminal_enhanced (Tn5250Terminal * This);
86 static int curses_terminal_is_ruler(Tn5250Terminal *This, Tn5250Display *display, int x, int y);
87 int curses_rgb_to_color(int r, int g, int b, int *rclr, int *rbold);
88 int curses_terminal_config(Tn5250Terminal *This, Tn5250Config *config);
89 void curses_terminal_print_screen(Tn5250Terminal *This, Tn5250Display *display);
90 void curses_postscript_print(FILE *out, int x, int y, char *string, attr_t attr);
91
92 #ifdef USE_OWN_KEY_PARSING
93 struct _Key {
94 int k_code;
95 char k_str[10];
96 };
97
98 typedef struct _Key Key;
99 #endif
100
101 #define MAX_K_BUF_LEN 20
102
103 struct _Tn5250TerminalPrivate {
104 int last_width, last_height;
105 #ifdef USE_OWN_KEY_PARSING
106 unsigned char k_buf[MAX_K_BUF_LEN];
107 int k_buf_len;
108
109 Key * k_map;
110 int k_map_len;
111 #endif
112 char * font_80;
113 char * font_132;
114 Tn5250Display *display;
115 Tn5250Config *config;
116 int quit_flag : 1;
117 int have_underscores : 1;
118 int underscores : 1;
119 int is_xterm : 1;
120 int display_ruler : 1;
121 int local_print : 1;
122 };
123
124 #ifdef USE_OWN_KEY_PARSING
125 /* This is an array mapping our key code to a termcap capability
126 * name. */
127 static Key curses_caps[] = {
128 { K_ENTER, "@8" },
129 { K_ENTER, "cr" },
130 { K_BACKTAB, "kB" },
131 { K_F1, "k1" },
132 { K_F2, "k2" },
133 { K_F3, "k3" },
134 { K_F4, "k4" },
135 { K_F5, "k5" },
136 { K_F6, "k6" },
137 { K_F7, "k7" },
138 { K_F8, "k8" },
139 { K_F9, "k9" },
140 { K_F10, "k;" },
141 { K_F11, "F1" },
142 { K_F12, "F2" },
143 { K_F13, "F3" },
144 { K_F14, "F4" },
145 { K_F15, "F5" },
146 { K_F16, "F6" },
147 { K_F17, "F7" },
148 { K_F18, "F8" },
149 { K_F19, "F9" },
150 { K_F20, "FA" },
151 { K_F21, "FB" },
152 { K_F22, "FC" },
153 { K_F23, "FD" },
154 { K_F24, "FE" },
155 { K_LEFT, "kl" },
156 { K_RIGHT, "kr" },
157 { K_UP, "ku" },
158 { K_DOWN, "kd" },
159 { K_ROLLDN, "kP" },
160 { K_ROLLUP, "kN" },
161 { K_BACKSPACE, "kb" },
162 { K_HOME, "kh" },
163 { K_END, "@7" },
164 { K_INSERT, "kI" },
165 { K_DELETE, "kD" },
166 { K_PRINT, "%9" },
167 { K_HELP, "%1" },
168 { K_CLEAR, "kC" },
169 { K_REFRESH, "&2" },
170 { K_FIELDEXIT, "@9" },
171 };
172
173 /* This is an array mapping some of our vt100 sequences to our internal
174 * key names. */
175 static Key curses_vt100[] = {
176 /* CTRL strings */
177 { K_ATTENTION, "\001" }, /* CTRL A */
178 { K_ROLLDN, "\002" }, /* CTRL B */
179 { K_SYSREQ, "\003" }, /* CTRL C */
180 { K_ROLLUP, "\004" }, /* CTRL D */
181 { K_ERASE, "\005" }, /* CTRL E */
182 { K_ROLLUP, "\006" }, /* CTRL F */
183 { K_FIELDEXIT, "\013" }, /* CTRL K */
184 { K_REFRESH, "\014" }, /* CTRL L */
185 { K_HOME, "\017" }, /* CTRL O */
186 { K_PRINT, "\020" }, /* CTRL P */
187 { K_RESET, "\022" }, /* CTRL R */
188 { K_MEMO, "\023" }, /* CTRL S */
189 { K_TESTREQ, "\024" }, /* CTRL T */
190 { K_ROLLDN, "\025" }, /* CTRL U */
191 { K_EXEC, "\027" }, /* CTRL W */
192 { K_FIELDPLUS, "\030" }, /* CTRL X */
193
194 /* ASCII DEL is not correctly reported as the DC key in some
195 * termcaps */
196 /* But it is backspace in some termcaps... */
197 /* { K_DELETE, "\177" }, */ /* ASCII DEL */
198 { K_DELETE, "\033\133\063\176" }, /* ASCII DEL Sequence: \E[3~ */
199
200
201 /* ESC strings */
202 { K_F1, "\033\061" }, /* ESC 1 */
203 { K_F2, "\033\062" }, /* ESC 2 */
204 { K_F3, "\033\063" }, /* ESC 3 */
205 { K_F4, "\033\064" }, /* ESC 4 */
206 { K_F5, "\033\065" }, /* ESC 5 */
207 { K_F6, "\033\066" }, /* ESC 6 */
208 { K_F7, "\033\067" }, /* ESC 7 */
209 { K_F8, "\033\070" }, /* ESC 8 */
210 { K_F9, "\033\071" }, /* ESC 9 */
211 { K_F10, "\033\060" }, /* ESC 0 */
212 { K_F11, "\033\055" }, /* ESC - */
213 { K_F12, "\033\075" }, /* ESC = */
214 { K_F13, "\033\041" }, /* ESC ! */
215 { K_F14, "\033\100" }, /* ESC @ */
216 { K_F15, "\033\043" }, /* ESC # */
217 { K_F16, "\033\044" }, /* ESC $ */
218 { K_F17, "\033\045" }, /* ESC % */
219 { K_F18, "\033\136" }, /* ESC ^ */
220 { K_F19, "\033\046" }, /* ESC & */
221 { K_F20, "\033\052" }, /* ESC * */
222 { K_F21, "\033\050" }, /* ESC ( */
223 { K_F22, "\033\051" }, /* ESC ) */
224 { K_F23, "\033\137" }, /* ESC _ */
225 { K_F24, "\033\053" }, /* ESC + */
226 { K_ATTENTION, "\033\101" }, /* ESC A */
227 { K_CLEAR, "\033\103" }, /* ESC C */
228 { K_DUPLICATE, "\033\104" }, /* ESC D */
229 { K_HELP, "\033\110" }, /* ESC H */
230 { K_INSERT, "\033\111" }, /* ESC I */
231 { K_REFRESH, "\033\114" }, /* ESC L */
232 { K_FIELDMINUS, "\033\115" }, /* ESC M */
233 { K_NEWLINE, "\033\116" }, /* ESC N */ /* Our extension */
234 { K_PRINT, "\033\120" }, /* ESC P */
235 { K_RESET, "\033\122" }, /* ESC R */
236 { K_SYSREQ, "\033\123" }, /* ESC S */
237 { K_TOGGLE, "\033\124" }, /* ESC T */
238 { K_FIELDEXIT, "\033\130" }, /* ESC X */
239 { K_NEWLINE, "\033\012" }, /* ESC ^J */
240 { K_NEWLINE, "\033\015" }, /* ESC ^M */
241 { K_INSERT, "\033\177" }, /* ESC DEL */
242 { K_NEXTFLD, "\033\025" }, /* ESC Ctrl-U */
243 { K_PREVFLD, "\033\010" }, /* ESC Ctrl-H */
244 { K_FIELDHOME, "\033\006" }, /* ESC Ctrl-F */
245 /* K_INSERT = ESC+DEL handled in code below. */
246 };
247 #endif
248
249 /****f* lib5250/tn5250_curses_terminal_new
250 * NAME
251 * tn5250_curses_terminal_new
252 * SYNOPSIS
253 * ret = tn5250_curses_terminal_new ();
254 * INPUTS
255 * None
256 * DESCRIPTION
257 * Create a new curses terminal object.
258 *****/
tn5250_curses_terminal_new()259 Tn5250Terminal *tn5250_curses_terminal_new()
260 {
261 Tn5250Terminal *r = tn5250_new(Tn5250Terminal, 1);
262 if (r == NULL)
263 return NULL;
264
265 r->data = tn5250_new(struct _Tn5250TerminalPrivate, 1);
266 if (r->data == NULL) {
267 free(r);
268 return NULL;
269 }
270
271 r->data->have_underscores = 0;
272 r->data->underscores = 0;
273 r->data->quit_flag = 0;
274 r->data->last_width = 0;
275 r->data->last_height = 0;
276 r->data->is_xterm = 0;
277 r->data->font_80 = NULL;
278 r->data->font_132 = NULL;
279 r->data->display_ruler = 0;
280 r->data->local_print = 0;
281 r->data->display = NULL;
282 r->data->config = NULL;
283
284 #ifdef USE_OWN_KEY_PARSING
285 r->data->k_buf_len = 0;
286 r->data->k_map_len = 0;
287 r->data->k_map = NULL;
288 #endif
289
290 r->conn_fd = -1;
291 r->init = curses_terminal_init;
292 r->term = curses_terminal_term;
293 r->destroy = curses_terminal_destroy;
294 r->width = curses_terminal_width;
295 r->height = curses_terminal_height;
296 r->flags = curses_terminal_flags;
297 r->update = curses_terminal_update;
298 r->update_indicators = curses_terminal_update_indicators;
299 r->waitevent = curses_terminal_waitevent;
300 r->getkey = curses_terminal_getkey;
301 r->putkey = NULL;
302 r->beep = curses_terminal_beep;
303 r->enhanced = curses_terminal_enhanced;
304 r->config = curses_terminal_config;
305 return r;
306 }
307
308 /****i* lib5250/curses_terminal_init
309 * NAME
310 * curses_terminal_init
311 * SYNOPSIS
312 * curses_terminal_init (This);
313 * INPUTS
314 * Tn5250Terminal * This -
315 * DESCRIPTION
316 * DOCUMENT ME!!!
317 *****/
curses_terminal_init(Tn5250Terminal * This)318 static void curses_terminal_init(Tn5250Terminal * This)
319 {
320 int i = 0, c, s;
321 char *str;
322 int x;
323
324 (void)initscr();
325 raw();
326
327 #ifdef USE_OWN_KEY_PARSING
328 if ((str = (unsigned char *)tgetstr ("ks", NULL)) != NULL)
329 tputs (str, 1, putchar);
330 fflush (stdout);
331 #else
332 keypad(stdscr, 1);
333 #endif
334
335 nodelay(stdscr, 1);
336 noecho();
337
338 /* Determine if we're talking to an xterm ;) */
339 if ((str = getenv("TERM")) != NULL &&
340 (!strcmp (str, "xterm") || !strcmp (str, "xterm-5250")
341 || !strcmp (str, "xterm-color")))
342 This->data->is_xterm = 1;
343
344 /* Initialize colors if the terminal supports it. */
345 if (has_colors()) {
346 start_color();
347 init_pair(COLOR_BLACK, colorlist[COLOR_BLACK].ref,
348 colorlist[COLOR_BLACK].ref);
349 init_pair(COLOR_GREEN, colorlist[COLOR_GREEN].ref,
350 colorlist[COLOR_BLACK].ref);
351 init_pair(COLOR_RED, colorlist[COLOR_RED ].ref,
352 colorlist[COLOR_BLACK].ref);
353 init_pair(COLOR_CYAN, colorlist[COLOR_CYAN ].ref,
354 colorlist[COLOR_BLACK].ref);
355 init_pair(COLOR_WHITE, colorlist[COLOR_WHITE].ref,
356 colorlist[COLOR_BLACK].ref);
357 init_pair(COLOR_MAGENTA,colorlist[COLOR_MAGENTA].ref,
358 colorlist[COLOR_BLACK].ref);
359 init_pair(COLOR_BLUE ,colorlist[COLOR_BLUE ].ref,
360 colorlist[COLOR_BLACK].ref);
361 init_pair(COLOR_YELLOW,colorlist[COLOR_YELLOW].ref,
362 colorlist[COLOR_BLACK].ref);
363 }
364
365 x=-1;
366 attribute_map[++x] = A_5250_GREEN;
367 attribute_map[++x] = A_5250_GREEN | A_REVERSE;
368 attribute_map[++x] = A_5250_WHITE;
369 attribute_map[++x] = A_5250_WHITE | A_REVERSE;
370 attribute_map[++x] = A_5250_GREEN | A_UNDERLINE;
371 attribute_map[++x] = A_5250_GREEN | A_UNDERLINE | A_REVERSE;
372 attribute_map[++x] = A_5250_WHITE | A_UNDERLINE;
373 attribute_map[++x] = 0x00;
374 attribute_map[++x] = A_5250_RED;
375 attribute_map[++x] = A_5250_RED | A_REVERSE;
376 attribute_map[++x] = A_5250_RED | A_BLINK;
377 attribute_map[++x] = A_5250_RED | A_BLINK | A_REVERSE;
378 attribute_map[++x] = A_5250_RED | A_UNDERLINE;
379 attribute_map[++x] = A_5250_RED | A_UNDERLINE | A_REVERSE;
380 attribute_map[++x] = A_5250_RED | A_UNDERLINE | A_BLINK;
381 attribute_map[++x] = 0x00;
382 attribute_map[++x] = A_5250_TURQ | A_VERTICAL;
383 attribute_map[++x] = A_5250_TURQ | A_VERTICAL | A_REVERSE;
384 attribute_map[++x] = A_5250_YELLOW | A_VERTICAL;
385 attribute_map[++x] = A_5250_YELLOW | A_VERTICAL | A_REVERSE;
386 attribute_map[++x] = A_5250_TURQ | A_UNDERLINE | A_VERTICAL;
387 attribute_map[++x] = A_5250_TURQ | A_UNDERLINE | A_REVERSE | A_VERTICAL;
388 attribute_map[++x] = A_5250_YELLOW | A_UNDERLINE | A_VERTICAL;
389 attribute_map[++x] = 0x00;
390 attribute_map[++x] = A_5250_PINK;
391 attribute_map[++x] = A_5250_PINK | A_REVERSE;
392 attribute_map[++x] = A_5250_BLUE;
393 attribute_map[++x] = A_5250_BLUE | A_REVERSE;
394 attribute_map[++x] = A_5250_PINK | A_UNDERLINE;
395 attribute_map[++x] = A_5250_PINK | A_UNDERLINE | A_REVERSE;
396 attribute_map[++x] = A_5250_BLUE | A_UNDERLINE;
397 attribute_map[++x] = 0x00;
398
399 This->data->quit_flag = 0;
400
401 /* Determine if the terminal supports underlining. */
402 if (This->data->have_underscores == 0) {
403 if ((unsigned char *)tgetstr ("us", NULL) == NULL)
404 This->data->underscores = 1;
405 else
406 This->data->underscores = 0;
407 }
408
409 #ifdef USE_OWN_KEY_PARSING
410 /* Allocate and populate an array of escape code => key code
411 * mappings. */
412 This->data->k_map_len = (sizeof (curses_vt100) / sizeof (Key)) * 2
413 + sizeof (curses_caps) / sizeof (Key) + 1;
414 This->data->k_map = (Key*)malloc (sizeof (Key)*This->data->k_map_len);
415
416 c = sizeof (curses_caps) / sizeof (Key);
417 s = sizeof (curses_vt100) / sizeof (Key);
418 for (i = 0; i < c; i++) {
419 This->data->k_map[i].k_code = curses_caps[i].k_code;
420 if ((str = (unsigned char *)tgetstr (curses_caps[i].k_str, NULL)) != NULL) {
421 TN5250_LOG(("Found string for cap '%s': '%s'.\n",
422 curses_caps[i].k_str, str));
423 strcpy (This->data->k_map[i].k_str, str);
424 } else
425 This->data->k_map[i].k_str[0] = '\0';
426 }
427
428 /* Populate vt100 escape codes, both ESC+ and C-g+ forms. */
429 for (i = 0; i < sizeof (curses_vt100) / sizeof (Key); i++) {
430 This->data->k_map[i + c].k_code =
431 This->data->k_map[i + c + s].k_code =
432 curses_vt100[i].k_code;
433 strcpy (This->data->k_map[i + c].k_str, curses_vt100[i].k_str);
434 strcpy (This->data->k_map[i + c + s].k_str, curses_vt100[i].k_str);
435
436 if (This->data->k_map[i + c + s].k_str[0] == '\033')
437 This->data->k_map[i + c + s].k_str[0] = K_CTRL('G');
438 else
439 This->data->k_map[i + c + s].k_str[0] = '\0';
440 }
441
442 /* Damn the exceptions to the rules. (ESC + DEL) */
443 This->data->k_map[This->data->k_map_len-1].k_code = K_INSERT;
444 This->data->k_map[This->data->k_map_len-s-1].k_code = K_INSERT;
445 if ((str = (unsigned char *)tgetstr ("kD", NULL)) != NULL) {
446 This->data->k_map[This->data->k_map_len-1].k_str[0] = '\033';
447 This->data->k_map[This->data->k_map_len-s-1].k_str[0] = K_CTRL('G');
448 strcpy (This->data->k_map[This->data->k_map_len-1].k_str + 1, str);
449 strcpy (This->data->k_map[This->data->k_map_len-s-1].k_str + 1, str);
450 } else
451 This->data->k_map[This->data->k_map_len-1].k_str[0] =
452 This->data->k_map[This->data->k_map_len-s-1].k_str[0] = 0;
453 #endif
454 }
455
456 /****i* lib5250/tn5250_curses_terminal_use_underscores
457 * NAME
458 * tn5250_curses_terminal_use_underscores
459 * SYNOPSIS
460 * tn5250_curses_terminal_use_underscores (This, f);
461 * INPUTS
462 * Tn5250Terminal * This - The curses terminal object.
463 * int f - Flag to use underscores
464 * DESCRIPTION
465 * This function instructs the curses terminal to use underscore
466 * characters (`_') for blank cells in under-lined fields instead of
467 * using the curses underline attribute. This is necessary on terminals
468 * which don't support the underline attribute.
469 *
470 * If this is not explicitly set, the curses terminal will determine
471 * if it should use underscores by checking for the "us" termcap
472 * capability. This may not always produce the desired effect.
473 *****/
tn5250_curses_terminal_use_underscores(Tn5250Terminal * This,int u)474 void tn5250_curses_terminal_use_underscores (Tn5250Terminal *This, int u)
475 {
476 This->data->have_underscores = 1;
477 This->data->underscores = u;
478 }
479
480 /****i* lib5250/tn5250_curses_terminal_display_ruler
481 * NAME
482 * tn5250_curses_terminal_display_ruler
483 * SYNOPSIS
484 * tn5250_curses_terminal_display_ruler (This, f);
485 * INPUTS
486 * Tn5250Terminal * This - The curses terminal object.
487 * int f - Flag, set to 1 to show ruler
488 * DESCRIPTION
489 * Call this function to tell a curses terminal to display a
490 * "ruler" that pinpoints where the cursor is on a given screen.
491 *****/
tn5250_curses_terminal_display_ruler(Tn5250Terminal * This,int f)492 void tn5250_curses_terminal_display_ruler (Tn5250Terminal *This, int f)
493 {
494 This->data->display_ruler = f;
495 }
496
497 /****i* lib5250/tn5250_curses_terminal_set_xterm_font
498 * NAME
499 * tn5250_curses_terminal_set_xterm_font
500 * SYNOPSIS
501 * tn5250_curses_terminal_set_xterm_font (This, font80, font132);
502 * INPUTS
503 * Tn5250Terminal * This - curses terminal object
504 * const char * font80 - string to send when using 80 col font
505 * const char * font132 - string to send when using 132 col font
506 * DESCRIPTION
507 * When using an xterm, it is sometimes desirable to change fonts when
508 * switching from 80 to 132 col mode. If this is not explicitly set,
509 * no font-change will be sent to the xterm.
510 *
511 * Font changes consist of "\x1b]50;<font string>\x07". You only need
512 * specify the "<font string>" portion as an argument to this function.
513 *****/
tn5250_curses_terminal_set_xterm_font(Tn5250Terminal * This,const char * font80,const char * font132)514 void tn5250_curses_terminal_set_xterm_font (Tn5250Terminal *This,
515 const char *font80, const char *font132)
516 {
517 This->data->font_80 = malloc(strlen(font80) + 6);
518 This->data->font_132 = malloc(strlen(font132) + 6);
519 sprintf(This->data->font_80, "\x1b]50;%s\x07", font80);
520 sprintf(This->data->font_132, "\x1b]50;%s\x07", font132);
521 TN5250_LOG(("font_80 = %s.\n",This->data->font_80));
522 TN5250_LOG(("font_132 = %s.\n",This->data->font_132));
523 }
524
525 /****i* lib5250/curses_terminal_term
526 * NAME
527 * curses_terminal_term
528 * SYNOPSIS
529 * curses_terminal_term (This);
530 * INPUTS
531 * Tn5250Terminal * This -
532 * DESCRIPTION
533 * DOCUMENT ME!!!
534 *****/
curses_terminal_term(Tn5250Terminal * This)535 static void curses_terminal_term(Tn5250Terminal /*@unused@*/ * This)
536 {
537 endwin();
538 }
539
540 /****i* lib5250/curses_terminal_destroy
541 * NAME
542 * curses_terminal_destroy
543 * SYNOPSIS
544 * curses_terminal_destroy (This);
545 * INPUTS
546 * Tn5250Terminal * This -
547 * DESCRIPTION
548 * DOCUMENT ME!!!
549 *****/
curses_terminal_destroy(Tn5250Terminal * This)550 static void curses_terminal_destroy(Tn5250Terminal * This)
551 {
552 #ifdef USE_OWN_KEY_PARSING
553 if (This->data->k_map != NULL)
554 free(This->data->k_map);
555 #endif
556 if (This->data->font_80 !=NULL)
557 free(This->data->font_80);
558 if (This->data->font_132 !=NULL)
559 free(This->data->font_132);
560 if (This->data != NULL)
561 free(This->data);
562 free(This);
563 }
564
565 /****i* lib5250/curses_terminal_width
566 * NAME
567 * curses_terminal_width
568 * SYNOPSIS
569 * ret = curses_terminal_width (This);
570 * INPUTS
571 * Tn5250Terminal * This -
572 * DESCRIPTION
573 * DOCUMENT ME!!!
574 *****/
curses_terminal_width(Tn5250Terminal * This)575 static int curses_terminal_width(Tn5250Terminal /*@unused@*/ * This)
576 {
577 int y, x;
578 getmaxyx(stdscr, y, x);
579 return x + 1;
580 }
581
582 /****i* lib5250/curses_terminal_height
583 * NAME
584 * curses_terminal_height
585 * SYNOPSIS
586 * ret = curses_terminal_height (This);
587 * INPUTS
588 * Tn5250Terminal * This -
589 * DESCRIPTION
590 * DOCUMENT ME!!!
591 *****/
curses_terminal_height(Tn5250Terminal * This)592 static int curses_terminal_height(Tn5250Terminal /*@unused@*/ * This)
593 {
594 int y, x;
595 getmaxyx(stdscr, y, x);
596 return y + 1;
597 }
598
599 /****i* lib5250/curses_terminal_flags
600 * NAME
601 * curses_terminal_flags
602 * SYNOPSIS
603 * ret = curses_terminal_flags (This);
604 * INPUTS
605 * Tn5250Terminal * This -
606 * DESCRIPTION
607 * DOCUMENT ME!!!
608 *****/
curses_terminal_flags(Tn5250Terminal * This)609 static int curses_terminal_flags(Tn5250Terminal /*@unused@*/ * This)
610 {
611 int f = 0;
612 if (has_colors() != 0)
613 f |= TN5250_TERMINAL_HAS_COLOR;
614 return f;
615 }
616
617 /****i* lib5250/curses_terminal_update
618 * NAME
619 * curses_terminal_update
620 * SYNOPSIS
621 * curses_terminal_update (This, display);
622 * INPUTS
623 * Tn5250Terminal * This -
624 * Tn5250Display * display -
625 * DESCRIPTION
626 * DOCUMENT ME!!!
627 *****/
curses_terminal_update(Tn5250Terminal * This,Tn5250Display * display)628 static void curses_terminal_update(Tn5250Terminal * This, Tn5250Display *display)
629 {
630 int my, mx;
631 int y, x;
632 attr_t curs_attr;
633 unsigned char a = 0x20, c;
634
635 This->data->display = display;
636
637 if (This->data->last_width != tn5250_display_width(display)
638 || This->data->last_height != tn5250_display_height(display)) {
639 clear();
640 if(This->data->is_xterm) {
641 if (This->data->font_132!=NULL) {
642 if (tn5250_display_width (display)>100)
643 printf(This->data->font_132);
644 else
645 printf(This->data->font_80);
646 }
647 printf ("\x1b[8;%d;%dt", tn5250_display_height (display)+1,
648 tn5250_display_width (display));
649 fflush (stdout);
650 #ifdef HAVE_RESIZETERM
651 resizeterm(tn5250_display_height(display)+1, tn5250_display_width(display)+1);
652 #endif
653 /* Make sure we get a SIGWINCH - We need curses to resize its
654 * buffer. */
655 raise (SIGWINCH);
656 refresh ();
657 }
658 This->data->last_width = tn5250_display_width(display);
659 This->data->last_height = tn5250_display_height(display);
660
661 /* XXX: this is somewhat of a hack. For some reason the change to
662 132 col lags a bit, causing our update to fail, so this just waits
663 for the update to finish... (is there a better way?) */
664
665 for (x=0; x<10; x++) {
666 refresh ();
667 if (tn5250_display_width(display)==curses_terminal_width(This)-1)
668 break;
669 usleep(10000);
670 }
671 }
672 attrset(A_NORMAL);
673 getmaxyx(stdscr, my, mx);
674 for (y = 0; y < tn5250_display_height(display); y++) {
675 if (y > my)
676 break;
677
678 move(y, 0);
679 for (x = 0; x < tn5250_display_width(display); x++) {
680 c = tn5250_display_char_at(display, y, x);
681 if ((c & 0xe0) == 0x20) { /* ATTRIBUTE */
682 a = (c & 0xff);
683 if (curses_terminal_is_ruler(This, display, x, y)) {
684 addch( A_REVERSE | attribute_map[0] | ' ');
685 } else {
686 addch(attribute_map[0] | ' ');
687 }
688 } else { /* DATA */
689 curs_attr = attribute_map[a - 0x20];
690 if (curs_attr == 0x00) { /* NONDISPLAY */
691 if (curses_terminal_is_ruler(This, display, x, y)) {
692 addch( A_REVERSE | attribute_map[0] | ' ');
693 } else {
694 addch(attribute_map[0] | ' ');
695 }
696 } else {
697 /* UNPRINTABLE -- print block */
698 if ((c==0x1f) || (c==0x3F)) {
699 c = ' ';
700 curs_attr ^= A_REVERSE;
701 }
702 /* UNPRINTABLE -- print blank */
703 else if ((c < 0x40 && c > 0x00) || c == 0xff) {
704 c = ' ';
705 } else {
706 c = tn5250_char_map_to_local (tn5250_display_char_map (display), c);
707 }
708 if ((curs_attr & A_VERTICAL) != 0) {
709 curs_attr |= A_UNDERLINE;
710 curs_attr &= ~A_VERTICAL;
711 }
712 /* This is a kludge since vga hardware doesn't support under-
713 * lining characters. It's pretty ugly. */
714 if (This->data->underscores) {
715 if ((curs_attr & A_UNDERLINE) != 0) {
716 curs_attr &= ~A_UNDERLINE;
717 if (c == ' ')
718 c = '_';
719 }
720 }
721 if (curses_terminal_is_ruler(This, display, x, y)) {
722 curs_attr |= A_REVERSE;
723 }
724 addch((chtype)(c | curs_attr));
725 }
726 } /* if ((c & 0xe0) ... */
727 } /* for (int x ... */
728 } /* for (int y ... */
729
730 move(tn5250_display_cursor_y(display), tn5250_display_cursor_x(display));
731
732 /* This performs the refresh () */
733 curses_terminal_update_indicators(This, display);
734 }
735
736
737 /****i* lib5250/curses_terminal_is_ruler
738 * NAME
739 * curses_terminal_is_ruler
740 * SYNOPSIS
741 * curses_terminal_is_ruler (display, x, y);
742 * INPUTS
743 * Tn5250Terminal * This -
744 * Tn5250Display * display -
745 * int x - position of char on X axis
746 * int y - position of char on Y axis
747 * DESCRIPTION
748 * Returns 1 if a char on the screen should be displayed as part
749 * of the ruler, or 0 if it should not.
750 *****/
curses_terminal_is_ruler(Tn5250Terminal * This,Tn5250Display * display,int x,int y)751 static int curses_terminal_is_ruler(Tn5250Terminal *This,
752 Tn5250Display *display, int x, int y) {
753
754 if (!(This->data->display_ruler)) return 0;
755
756 if (x==tn5250_display_cursor_x(display)) {
757 return 1;
758 }
759 if (y==tn5250_display_cursor_y(display)) {
760 return 1;
761 }
762
763 return 0;
764 }
765
766
767 /****i* lib5250/curses_terminal_update_indicators
768 * NAME
769 * curses_terminal_update_indicators
770 * SYNOPSIS
771 * curses_terminal_update_indicators (This, display);
772 * INPUTS
773 * Tn5250Terminal * This -
774 * Tn5250Display * display -
775 * DESCRIPTION
776 * DOCUMENT ME!!!
777 *****/
curses_terminal_update_indicators(Tn5250Terminal * This,Tn5250Display * display)778 static void curses_terminal_update_indicators(Tn5250Terminal /*@unused@*/ * This, Tn5250Display *display)
779 {
780 int inds = tn5250_display_indicators(display);
781 char ind_buf[80];
782
783 memset(ind_buf, ' ', sizeof(ind_buf));
784 memcpy(ind_buf, "5250", 4);
785 if ((inds & TN5250_DISPLAY_IND_MESSAGE_WAITING) != 0)
786 memcpy(ind_buf + 23, "MW", 2);
787 if ((inds & TN5250_DISPLAY_IND_INHIBIT) != 0)
788 memcpy(ind_buf + 9, "X II", 4);
789 else if ((inds & TN5250_DISPLAY_IND_X_CLOCK) != 0)
790 memcpy(ind_buf + 9, "X CLOCK", 7);
791 else if ((inds & TN5250_DISPLAY_IND_X_SYSTEM) != 0)
792 memcpy(ind_buf + 9, "X SYSTEM", 8);
793 if ((inds & TN5250_DISPLAY_IND_INSERT) != 0)
794 memcpy(ind_buf + 30, "IM", 2);
795 if ((inds & TN5250_DISPLAY_IND_FER) != 0)
796 memcpy(ind_buf + 33, "FER", 3);
797 if ((inds & TN5250_DISPLAY_IND_MACRO) != 0)
798 memcpy(ind_buf + 54, tn5250_macro_printstate (display), 11);
799 sprintf(ind_buf+72,"%03.3d/%03.3d",tn5250_display_cursor_x(display)+1,
800 tn5250_display_cursor_y(display)+1);
801
802 attrset( (attr_t)COLOR_PAIR(COLOR_WHITE) );
803 mvaddnstr(tn5250_display_height(display), 0, ind_buf, 80);
804 move(tn5250_display_cursor_y(display), tn5250_display_cursor_x(display));
805 attrset(A_NORMAL);
806 refresh();
807 }
808
809 /****i* lib5250/curses_terminal_waitevent
810 * NAME
811 * curses_terminal_waitevent
812 * SYNOPSIS
813 * ret = curses_terminal_waitevent (This);
814 * INPUTS
815 * Tn5250Terminal * This -
816 * DESCRIPTION
817 * DOCUMENT ME!!!
818 *****/
curses_terminal_waitevent(Tn5250Terminal * This)819 static int curses_terminal_waitevent(Tn5250Terminal * This)
820 {
821 fd_set fdr;
822 int result = 0;
823 int sm;
824
825
826 if (This->data->quit_flag)
827 return TN5250_TERMINAL_EVENT_QUIT;
828
829 FD_ZERO(&fdr);
830
831 FD_SET(0, &fdr);
832 sm = 1;
833 if (This->conn_fd >= 0) {
834 FD_SET(This->conn_fd, &fdr);
835 sm = This->conn_fd + 1;
836 }
837
838 select(sm, &fdr, NULL, NULL, NULL);
839
840 if (FD_ISSET(0, &fdr))
841 result |= TN5250_TERMINAL_EVENT_KEY;
842
843 if (This->conn_fd >= 0 && FD_ISSET(This->conn_fd, &fdr))
844 result |= TN5250_TERMINAL_EVENT_DATA;
845
846 return result;
847 }
848
849 #ifndef USE_OWN_KEY_PARSING
850 /****i* lib5250/curses_terminal_getkey
851 * NAME
852 * curses_terminal_getkey
853 * SYNOPSIS
854 * ret = curses_terminal_getkey (This);
855 * INPUTS
856 * Tn5250Terminal * This -
857 * DESCRIPTION
858 * DOCUMENT ME!!!
859 *****/
curses_terminal_getkey(Tn5250Terminal * This)860 static int curses_terminal_getkey(Tn5250Terminal * This)
861 {
862 int key;
863
864 key = getch();
865
866 while (1) {
867 switch (key) {
868
869 case 0x0d:
870 case 0x0a:
871 return K_ENTER;
872
873 case 0x1b:
874 if ((key = curses_terminal_get_esc_key(This, 1)) != ERR)
875 return key;
876 break;
877
878 case K_CTRL('A'):
879 return K_ATTENTION;
880 case K_CTRL('B'):
881 return K_ROLLDN;
882 case K_CTRL('C'):
883 return K_SYSREQ;
884 case K_CTRL('D'):
885 return K_ROLLUP;
886 case K_CTRL('E'):
887 return K_ERASE;
888 case K_CTRL('F'):
889 return K_ROLLUP;
890 case K_CTRL('K'):
891 return K_FIELDEXIT;
892 case K_CTRL('L'):
893 return K_REFRESH;
894 case K_CTRL('O'):
895 return K_HOME;
896 case K_CTRL('P'):
897 return K_PRINT;
898 case K_CTRL('R'):
899 return K_RESET; /* Error Reset */
900 case K_CTRL('S'):
901 return K_MEMO;
902 case K_CTRL('T'):
903 return K_TESTREQ;
904 case K_CTRL('U'):
905 return K_ROLLDN;
906 case K_CTRL('W'):
907 return K_EXEC;
908 case K_CTRL('X'):
909 return K_FIELDPLUS;
910
911 case K_CTRL('Q'):
912 This->data->quit_flag = 1;
913 return -1;
914
915 case K_CTRL('G'): /* C-g <function-key-shortcut> */
916 if ((key = curses_terminal_get_esc_key(This, 0)) != ERR)
917 return key;
918 break;
919
920 case ERR:
921 return -1;
922
923 case 127:
924 return K_DELETE;
925
926 case KEY_A1:
927 return K_HOME;
928
929 case KEY_A3:
930 return K_ROLLDN;
931
932 case KEY_C1:
933 return K_END;
934
935 case KEY_C3:
936 return K_ROLLUP;
937
938 case KEY_ENTER:
939 return K_FIELDEXIT;
940
941 case KEY_END:
942 return K_END;
943
944 default:
945 return key;
946 }
947 }
948 }
949 #endif
950
951 /****i* lib5250/curses_terminal_beep
952 * NAME
953 * curses_terminal_beep
954 * SYNOPSIS
955 * curses_terminal_beep (This);
956 * INPUTS
957 * Tn5250Terminal * This -
958 * DESCRIPTION
959 * DOCUMENT ME!!!
960 *****/
curses_terminal_beep(Tn5250Terminal * This)961 static void curses_terminal_beep (Tn5250Terminal *This)
962 {
963 TN5250_LOG (("CURSES: beep\n"));
964 beep ();
965 refresh ();
966 }
967
968
969 /***** lib5250/curses_terminal_enhanced
970 * NAME
971 * curses_terminal_enhanced
972 * SYNOPSIS
973 * ret = curses_terminal_enhanced (This);
974 * INPUTS
975 * Tn5250Terminal * This -
976 * DESCRIPTION
977 * Return 1 if we support the enhanced 5250 protocol, 0 otherwise.
978 *****/
979 static int
curses_terminal_enhanced(Tn5250Terminal * This)980 curses_terminal_enhanced (Tn5250Terminal * This)
981 {
982 return (0);
983 }
984
985 #ifndef USE_OWN_KEY_PARSING
986 /****i* lib5250/curses_terminal_get_esc_key
987 * NAME
988 * curses_terminal_get_esc_key
989 * SYNOPSIS
990 * ret = curses_terminal_get_esc_key (This, is_esc);
991 * INPUTS
992 * Tn5250Terminal * This -
993 * int is_esc -
994 * DESCRIPTION
995 * If a vt100 escape key sequence was introduced (using either
996 * <Esc> or <Ctrl+g>), handle the next key in the sequence.
997 *****/
curses_terminal_get_esc_key(Tn5250Terminal * This,int is_esc)998 static int curses_terminal_get_esc_key(Tn5250Terminal * This, int is_esc)
999 {
1000 int y, x, key, display_key;
1001 fd_set fdr;
1002
1003 getyx(stdscr, y, x);
1004 attrset(COLOR_PAIR(COLOR_WHITE));
1005 if (is_esc)
1006 mvaddstr(24, 60, "Esc ");
1007 else
1008 mvaddstr(24, 60, "C-g ");
1009 move(y, x);
1010 refresh();
1011
1012 FD_ZERO(&fdr);
1013 FD_SET(0, &fdr);
1014 select(1, &fdr, NULL, NULL, NULL);
1015 key = getch();
1016
1017 if (isalpha(key))
1018 key = toupper(key);
1019
1020 display_key = key;
1021 switch (key) {
1022
1023 /* Function keys */
1024 case '1':
1025 key = K_F1;
1026 break;
1027 case '2':
1028 key = K_F2;
1029 break;
1030 case '3':
1031 key = K_F3;
1032 break;
1033 case '4':
1034 key = K_F4;
1035 break;
1036 case '5':
1037 key = K_F5;
1038 break;
1039 case '6':
1040 key = K_F6;
1041 break;
1042 case '7':
1043 key = K_F7;
1044 break;
1045 case '8':
1046 key = K_F8;
1047 break;
1048 case '9':
1049 key = K_F9;
1050 break;
1051 case '0':
1052 key = K_F10;
1053 break;
1054 case '-':
1055 key = K_F11;
1056 break;
1057 case '=':
1058 key = K_F12;
1059 break;
1060 case '!':
1061 key = K_F13;
1062 break;
1063 case '@':
1064 key = K_F14;
1065 break;
1066 case '#':
1067 key = K_F15;
1068 break;
1069 case '$':
1070 key = K_F16;
1071 break;
1072 case '%':
1073 key = K_F17;
1074 break;
1075 case '^':
1076 key = K_F18;
1077 break;
1078 case '&':
1079 key = K_F19;
1080 break;
1081 case '*':
1082 key = K_F20;
1083 break;
1084 case '(':
1085 key = K_F21;
1086 break;
1087 case ')':
1088 key = K_F22;
1089 break;
1090 case '_':
1091 key = K_F23;
1092 break;
1093 case '+':
1094 key = K_F24;
1095 break;
1096
1097 case K_CTRL('U'):
1098 key = K_NEXTFLD;
1099 break;
1100 case K_CTRL('H'):
1101 key = K_PREVFLD;
1102 break;
1103 case K_CTRL('F'):
1104 key = K_FIELDHOME;
1105 break;
1106
1107 /* AS/400 strangeness */
1108 case 'A':
1109 key = K_ATTENTION;
1110 break;
1111 case 'C':
1112 key = K_CLEAR;
1113 break;
1114 case 'D':
1115 key = K_DUPLICATE;
1116 break;
1117 case 'H':
1118 key = K_HELP;
1119 break;
1120 case 'I':
1121 key = K_INSERT;
1122 break;
1123 case 'L':
1124 key = K_REFRESH;
1125 break;
1126 case 'M':
1127 key = K_FIELDMINUS;
1128 break;
1129 case 'P':
1130 key = K_PRINT;
1131 break;
1132 case 'R':
1133 key = K_RESET;
1134 break;
1135 case 'S':
1136 key = K_SYSREQ;
1137 break;
1138 case 'T':
1139 key = K_TOGGLE;
1140 break;
1141 case 'X':
1142 key = K_FIELDEXIT;
1143 break;
1144
1145 case 127:
1146 key = K_INSERT;
1147 break; /* ESC DEL */
1148 case KEY_DC:
1149 key = K_INSERT;
1150 break; /* ESC DEL, also */
1151 case K_CTRL('J'):
1152 key = K_NEWLINE;
1153 break;
1154
1155 case 'Q':
1156 This->data->quit_flag = 1;
1157 key = -1;
1158 break;
1159
1160 case ERR:
1161 default:
1162 beep();
1163 key = -1;
1164 break;
1165 }
1166
1167 if (key == -1)
1168 mvaddstr(24, 64, "???");
1169 else
1170 mvaddch(24, 64, (chtype)display_key);
1171 move(y, x);
1172 refresh();
1173 return key;
1174 }
1175 #endif
1176
1177 #ifdef USE_OWN_KEY_PARSING
curses_get_key(Tn5250Terminal * This,int rmflag)1178 static int curses_get_key (Tn5250Terminal *This, int rmflag)
1179 {
1180 int i, j;
1181 int have_incomplete_match = -1;
1182 int have_complete_match = -1;
1183 int complete_match_len;
1184
1185 /* Fast path */
1186 if (This->data->k_buf_len == 0)
1187 return -1;
1188
1189 /* Look up escape codes. */
1190 for (i = 0; i < This->data->k_map_len; i++) {
1191
1192 /* Skip empty entries. */
1193 if (This->data->k_map[i].k_str[0] == '\0')
1194 continue;
1195
1196 for (j = 0; j < MAX_K_BUF_LEN + 1; j++) {
1197 if (This->data->k_map[i].k_str[j] == '\0') {
1198 have_complete_match = i;
1199 complete_match_len = j;
1200 break;
1201 }
1202 if (j == This->data->k_buf_len) {
1203 have_incomplete_match = i;
1204 TN5250_LOG (("Have incomplete match ('%s')\n",
1205 This->data->k_map[i].k_str));
1206 break;
1207 }
1208 if (This->data->k_map[i].k_str[j] != This->data->k_buf[j])
1209 break; /* No match */
1210 }
1211
1212 }
1213
1214 if (have_incomplete_match == -1 && have_complete_match == -1) {
1215 /* At this point, we know that we don't have an escape sequence,
1216 * so just return the next character. */
1217 i = This->data->k_buf[0];
1218 if (rmflag) {
1219 memmove (This->data->k_buf, This->data->k_buf + 1, MAX_K_BUF_LEN - 1);
1220 This->data->k_buf_len --;
1221 }
1222 return i;
1223 }
1224
1225 if (have_incomplete_match != -1)
1226 return -1;
1227
1228 if (have_complete_match != -1) {
1229 if (rmflag) {
1230 if (This->data->k_buf_len - complete_match_len > 0) {
1231 memmove (This->data->k_buf, This->data->k_buf + complete_match_len,
1232 This->data->k_buf_len - complete_match_len);
1233 }
1234 This->data->k_buf_len -= complete_match_len;
1235 }
1236 return This->data->k_map[have_complete_match].k_code;
1237 }
1238
1239 return -1;
1240 }
1241
curses_terminal_getkey(Tn5250Terminal * This)1242 static int curses_terminal_getkey (Tn5250Terminal *This)
1243 {
1244 int ch;
1245
1246 /* Retreive all keys from the keyboard buffer. */
1247 while (This->data->k_buf_len < MAX_K_BUF_LEN && (ch = getch ()) != ERR) {
1248 TN5250_LOG(("curses_getch: received 0x%02X.\n", ch));
1249
1250 /* FIXME: Here would be the proper place to get mouse events :) */
1251
1252 /* HACK! Why are we gettings these 0410s still? ncurses bug? */
1253 if (ch < 0 || ch > 255)
1254 continue;
1255
1256 This->data->k_buf[This->data->k_buf_len++] = ch;
1257 }
1258
1259 ch = curses_get_key (This, 1);
1260 switch (ch) {
1261 case K_CTRL('Q'):
1262 This->data->quit_flag = 1;
1263 return -1;
1264 case 0x0a:
1265 return 0x0d;
1266 case K_PRINT:
1267 if (This->data->local_print) {
1268 curses_terminal_print_screen(This, This->data->display);
1269 ch = K_RESET;
1270 }
1271 break;
1272 }
1273 return ch;
1274 }
1275 #endif
1276
1277 /****i* lib5250/curses_rgb_to_color
1278 * NAME
1279 * curses_rgb_to_color
1280 * SYNOPSIS
1281 * curses_rgb_to_color (r, g, b, &clr, &bld);
1282 * INPUTS
1283 * int r -
1284 * int g -
1285 * int b -
1286 * int * rclr -
1287 * int * rbold -
1288 * DESCRIPTION
1289 * DOCUMENT ME!!!
1290 *****/
curses_rgb_to_color(int r,int g,int b,int * rclr,int * rbold)1291 int curses_rgb_to_color(int r, int g, int b, int *rclr, int *rbold) {
1292
1293 int clr;
1294
1295 clr = ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff);
1296 *rbold = A_NORMAL;
1297
1298 switch (clr) {
1299 case 0xFFFFFF:
1300 *rclr = COLOR_WHITE; *rbold = A_BOLD;
1301 break;
1302 case 0xFFFF00:
1303 *rclr = COLOR_YELLOW; *rbold = A_BOLD;
1304 break;
1305 case 0xFF00FF:
1306 *rclr = COLOR_MAGENTA; *rbold = A_BOLD;
1307 break;
1308 case 0xFF0000:
1309 *rclr = COLOR_RED; *rbold = A_BOLD;
1310 break;
1311 case 0x00FFFF:
1312 *rclr = COLOR_CYAN; *rbold = A_BOLD;
1313 break;
1314 case 0x00FF00:
1315 *rclr = COLOR_GREEN; *rbold = A_BOLD;
1316 break;
1317 case 0x0000FF:
1318 *rclr = COLOR_BLUE; *rbold = A_BOLD;
1319 break;
1320 case 0x808080:
1321 *rclr = COLOR_WHITE;
1322 break;
1323 case 0xC0C0C0:
1324 *rclr = COLOR_WHITE;
1325 break;
1326 case 0x808000:
1327 *rclr = COLOR_YELLOW;
1328 break;
1329 case 0x800080:
1330 *rclr = COLOR_MAGENTA;
1331 break;
1332 case 0x800000:
1333 *rclr = COLOR_RED;
1334 break;
1335 case 0x008080:
1336 *rclr = COLOR_CYAN;
1337 break;
1338 case 0x008000:
1339 *rclr = COLOR_GREEN;
1340 break;
1341 case 0x000080:
1342 *rclr = COLOR_BLUE;
1343 break;
1344 case 0x000000:
1345 *rclr = COLOR_BLACK;
1346 break;
1347 default:
1348 return -1;
1349 }
1350
1351 return 0;
1352 }
1353
1354 /****i* lib5250/tn5250_curses_terminal_load_colorlist
1355 * NAME
1356 * tn5250_curses_terminal_load_colorlist
1357 * SYNOPSIS
1358 * tn5250_curses_terminal_load_colorlist(config);
1359 * INPUTS
1360 * Tn5250Config * config -
1361 * DESCRIPTION
1362 * DOCUMENT ME!!!
1363 *****/
tn5250_curses_terminal_load_colorlist(Tn5250Config * config)1364 void tn5250_curses_terminal_load_colorlist(Tn5250Config *config) {
1365
1366 int r, g, b, x, clr, bld;
1367
1368 if (tn5250_config_get_bool(config, "black_on_white")) {
1369 for (x=COLOR_BLACK+1; x<=COLOR_WHITE; x++) {
1370 colorlist[x].ref = COLOR_BLACK;
1371 colorlist[x].bld = A_NORMAL;
1372 }
1373 colorlist[COLOR_BLACK].ref = COLOR_WHITE;
1374 colorlist[COLOR_BLACK].bld = A_BOLD;
1375 }
1376
1377 if (tn5250_config_get_bool(config, "white_on_black")) {
1378 for (x=COLOR_BLACK+1; x<=COLOR_WHITE; x++) {
1379 colorlist[x].ref = COLOR_WHITE;
1380 colorlist[x].bld = A_BOLD;
1381 }
1382 colorlist[COLOR_BLACK].ref = COLOR_BLACK;
1383 colorlist[COLOR_BLACK].bld = A_NORMAL;
1384 }
1385
1386 x=0;
1387 while (colorlist[x].name != NULL) {
1388 if (tn5250_parse_color(config, colorlist[x].name, &r, &g, &b)!=-1) {
1389 if (curses_rgb_to_color(r,g,b, &clr, &bld) != -1) {
1390 colorlist[x].ref = clr;
1391 colorlist[x].bld = bld;
1392 }
1393 }
1394 x++;
1395 }
1396
1397 }
1398
1399
1400 /****i* lib5250/curses_terminal_config
1401 * NAME
1402 * curses_terminal_config
1403 * SYNOPSIS
1404 * curses_terminal_config(This, config);
1405 * INPUTS
1406 * Tn5250Terminal * This -
1407 * Tn5250Display * config -
1408 * DESCRIPTION
1409 * Assign a set of configuration data to the terminal
1410 *****/
curses_terminal_config(Tn5250Terminal * This,Tn5250Config * config)1411 int curses_terminal_config(Tn5250Terminal *This, Tn5250Config *config) {
1412 This->data->config = config;
1413 if (tn5250_config_get_bool(config, "local_print_key"))
1414 This->data->local_print = 1;
1415 return 0;
1416 }
1417
1418
1419 /****i* lib5250/curses_terminal_print_screen
1420 * NAME
1421 * curses_terminal_print_screen
1422 * SYNOPSIS
1423 * curses_terminal_print_screen(This, This->data->display);
1424 * INPUTS
1425 * Tn5250Terminal * This -
1426 * Tn5250Display * display -
1427 * DESCRIPTION
1428 * Generate PostScript output of current screen image.
1429 *****/
curses_terminal_print_screen(Tn5250Terminal * This,Tn5250Display * display)1430 void curses_terminal_print_screen(Tn5250Terminal *This, Tn5250Display *display) {
1431
1432 int x, y, c, a;
1433 attr_t curs_attr;
1434 int px, py;
1435 int leftmar, topmar;
1436 FILE *out;
1437 const char *outcmd;
1438 double pgwid, pglen;
1439 double colwidth, rowheight, fontsize;
1440 int textlen;
1441 char *prttext;
1442
1443 if (display==NULL)
1444 return;
1445
1446 /* default values for printing screens are: */
1447
1448 outcmd = "lpr";
1449 pglen = 11 * 72;
1450 pgwid = 8.5 * 72;
1451 leftmar = 18;
1452 topmar = 36;
1453 if (tn5250_display_width(display) == 132)
1454 fontsize = 7.0;
1455 else
1456 fontsize = 10.0;
1457
1458 /* override defaults with values from config if available */
1459
1460 if (This->data->config != NULL) {
1461 int fs80=0, fs132=0;
1462 if (tn5250_config_get(This->data->config, "outputcommand"))
1463 outcmd = tn5250_config_get(This->data->config, "outputcommand");
1464 if (tn5250_config_get(This->data->config, "pagewidth"))
1465 pgwid = atoi(tn5250_config_get(This->data->config, "pagewidth"));
1466 if (tn5250_config_get(This->data->config, "pagelength"))
1467 pglen = atoi(tn5250_config_get(This->data->config, "pagelength"));
1468 if (tn5250_config_get(This->data->config, "leftmargin"))
1469 leftmar = atoi(tn5250_config_get(This->data->config, "leftmargin"));
1470 if (tn5250_config_get(This->data->config, "topmargin"))
1471 topmar = atoi(tn5250_config_get(This->data->config, "topmargin"));
1472 if (tn5250_config_get(This->data->config, "psfontsize_80"))
1473 fs80 = atoi(tn5250_config_get(This->data->config, "psfontsize_80"));
1474 if (tn5250_config_get(This->data->config, "psfontsize_80"))
1475 fs132 =atoi(tn5250_config_get(This->data->config, "psfontsize_132"));
1476 if (tn5250_display_width(display)==132 && fs132!=0)
1477 fontsize = fs132;
1478 if (tn5250_display_width(display)==80 && fs80!=0)
1479 fontsize = fs80;
1480 }
1481
1482 colwidth = (pgwid - leftmar*2) / tn5250_display_width(display);
1483 rowheight = (pglen - topmar*2) / 66;
1484
1485
1486 /* allocate enough memory to store the largest possible string that we
1487 could output. Note that it could be twice the size of the screen
1488 if every single character needs to be escaped... */
1489 prttext = malloc((2 * tn5250_display_width(display) *
1490 tn5250_display_height(display)) + 1);
1491
1492 out = popen(outcmd, "w");
1493 if (out == NULL)
1494 return;
1495
1496 fprintf(out, "%%!PS-Adobe-3.0\n");
1497 fprintf(out, "%%%%Pages: 1\n");
1498 fprintf(out, "%%%%Title: TN5250 Print Screen\n");
1499 fprintf(out, "%%%%BoundingBox: 0 0 %.0f %.0f\n", pgwid, pglen);
1500 fprintf(out, "%%%%LanguageLevel: 2\n");
1501 fprintf(out, "%%%%EndComments\n\n");
1502 fprintf(out, "%%%%BeginProlog\n");
1503 fprintf(out, "%%%%BeginResource: procset general 1.0.0\n");
1504 fprintf(out, "%%%%Title: (General Procedures)\n");
1505 fprintf(out, "%%%%Version: 1.0\n");
1506 fprintf(out, "%% Courier is a fixed-pitch font, so one character is as\n");
1507 fprintf(out, "%% good as another for determining the height/width\n");
1508 fprintf(out, "/Courier %.2f selectfont\n", fontsize);
1509 fprintf(out, "/chrwid (W) stringwidth pop def\n");
1510 fprintf(out, "/pglen %.2f def\n", pglen);
1511 fprintf(out, "/pgwid %.2f def\n", pgwid);
1512 fprintf(out, "/chrhgt %.2f def\n", rowheight);
1513 fprintf(out, "/leftmar %d def\n", leftmar + 2);
1514 fprintf(out, "/topmar %d def\n", topmar);
1515 fprintf(out, "/exploc { %% expand x y to dot positions\n"
1516 " chrhgt mul\n"
1517 " topmar add\n"
1518 " 3 add\n"
1519 " pglen exch sub\n"
1520 " exch\n"
1521 " chrwid mul\n"
1522 " leftmar add\n"
1523 " 3 add\n"
1524 " exch\n"
1525 "} bind def\n");
1526 fprintf(out, "/prtnorm { %% print text normally (text) x y color\n"
1527 " setgray\n"
1528 " exploc moveto\n"
1529 " show\n"
1530 "} bind def\n");
1531 fprintf(out, "/drawunderline { %% draw underline: (string) x y color\n"
1532 " gsave\n"
1533 " 0 setlinewidth\n"
1534 " setgray\n"
1535 " exploc\n"
1536 " 2 sub\n"
1537 " moveto\n"
1538 " stringwidth pop 0\n"
1539 " rlineto\n"
1540 " stroke\n"
1541 " grestore\n"
1542 "} bind def\n");
1543 fprintf(out, "/blkbox { %% draw a black box behind the text\n"
1544 " gsave\n"
1545 " newpath\n"
1546 " 0 setgray\n"
1547 " exploc\n"
1548 " 3 sub\n"
1549 " moveto\n"
1550 " 0 chrhgt rlineto\n"
1551 " stringwidth pop 0 rlineto\n"
1552 " 0 0 chrhgt sub rlineto\n"
1553 " closepath\n"
1554 " fill\n"
1555 " grestore\n"
1556 "} bind def\n");
1557 fprintf(out, "/borderbox { %% Print a border around screen dump\n"
1558 " gsave\n"
1559 " newpath\n"
1560 " 0 setlinewidth\n"
1561 " 0 setgray\n"
1562 " leftmar\n"
1563 " topmar chrhgt sub pglen exch sub\n"
1564 " moveto\n"
1565 " chrwid %d mul 6 add 0 rlineto\n"
1566 " 0 0 chrhgt %d mul 6 add sub rlineto\n"
1567 " 0 chrwid %d mul 6 add sub 0 rlineto\n"
1568 " closepath\n"
1569 " stroke\n"
1570 " grestore\n"
1571 "} bind def\n",
1572 tn5250_display_width(display),
1573 tn5250_display_height(display)+1,
1574 tn5250_display_width(display));
1575 fprintf(out, "%%%%EndResource\n");
1576 fprintf(out, "%%%%EndProlog\n\n");
1577 fprintf(out, "%%%%Page 1 1\n");
1578 fprintf(out, "%%%%BeginPageSetup\n");
1579 fprintf(out, "/pgsave save def\n");
1580 fprintf(out, "%%%%EndPageSetup\n");
1581
1582 curs_attr = 0x00;
1583 textlen = 0;
1584 px = -1;
1585
1586 for (y = 0; y < tn5250_display_height(display); y++) {
1587
1588 for (x = 0; x < tn5250_display_width(display); x++) {
1589
1590 c = tn5250_display_char_at(display, y, x);
1591 if ((c & 0xe0) == 0x20) {
1592 if (textlen > 0) {
1593 curses_postscript_print(out, px, py, prttext, curs_attr);
1594 textlen = 0;
1595 }
1596 a = (c & 0xff);
1597 curs_attr = attribute_map[a - 0x20];
1598 px = -1;
1599 } else {
1600 if (px == -1) {
1601 px = x;
1602 py = y;
1603 }
1604 if ((c < 0x40 && c > 0x00) || c == 0xff) {
1605 c = ' ';
1606 } else {
1607 c = tn5250_char_map_to_local (
1608 tn5250_display_char_map (display), c);
1609 }
1610 if (c == '\\' || c == '(' || c == ')') {
1611 prttext[textlen] = '\\';
1612 textlen++;
1613 }
1614 prttext[textlen] = c;
1615 textlen++;
1616 prttext[textlen] = '\0';
1617 }
1618 }
1619 if (textlen > 0) {
1620 curses_postscript_print(out, px, py, prttext, curs_attr);
1621 textlen = 0;
1622 }
1623 px = -1;
1624 }
1625
1626 fprintf(out, "borderbox\n");
1627 fprintf(out, "pgsave restore\n");
1628 fprintf(out, "showpage\n");
1629 fprintf(out, "%%%%PageTrailer\n");
1630 fprintf(out, "%%%%Trailer\n");
1631 fprintf(out, "%%%%Pages: 1\n");
1632 fprintf(out, "%%%%EOF\n");
1633
1634 pclose(out);
1635
1636 free(prttext);
1637
1638 attrset(attribute_map[0]);
1639 clear();
1640 mvprintw(0, 0, "Print Screen Successful!");
1641 mvprintw(1, 0, "Press ENTER to continue.");
1642 refresh();
1643
1644 while (curses_terminal_getkey(This)!=K_ENTER) { /* wait */ }
1645
1646 curses_terminal_update(This, display);
1647 }
1648
1649
1650 /****i* lib5250/curses_postscript_print
1651 * NAME
1652 * curses_postscript_print
1653 * SYNOPSIS
1654 * curses_postscript_print(out, px, py, "Print this", A_NORMAL);
1655 * INPUTS
1656 * FILE * out -
1657 * int x -
1658 * int y -
1659 * char * string -
1660 * attr_t attr -
1661 * DESCRIPTION
1662 * Adds a printed string to the postscript output generated by
1663 * curses_terminal_print_screen. Converts the curses attributes
1664 * to attributes understood by postscript (using the procedures
1665 * we put in the prolog of the ps document)
1666 *****/
1667
curses_postscript_print(FILE * out,int x,int y,char * string,attr_t attr)1668 void curses_postscript_print(FILE *out, int x, int y, char *string, attr_t attr) {
1669 int color;
1670
1671 if (attr == 0x00) /* NONDISPLAY */
1672 return;
1673
1674 color = 0;
1675 if (attr & A_REVERSE) { /* Print white text on black background */
1676 color = 1;
1677 fprintf(out, "(%s) %d %d blkbox\n", string, x, y);
1678 }
1679
1680 fprintf(out, "(%s) %d %d %d prtnorm\n", string, x, y, color);
1681
1682 if (attr & A_UNDERLINE) /* draw underline below text */
1683 fprintf(out, "(%s) %d %d %d drawunderline\n", string, x, y, color);
1684
1685 }
1686
1687
1688 #endif /* USE_CURSES */
1689
1690 /* vi:set cindent sts=3 sw=3: */
1691