"Fossies" - the Fresh Open Source Software Archive 
Member "xterm-379/xtermcap.c" (2 Jan 2023, 16030 Bytes) of package /linux/misc/xterm-379.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "xtermcap.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
377_vs_379.
1 /* $XTermId: xtermcap.c,v 1.58 2023/01/02 18:19:19 tom Exp $ */
2
3 /*
4 * Copyright 2007-2020,2023 by Thomas E. Dickey
5 *
6 * All Rights Reserved
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * Except as contained in this notice, the name(s) of the above copyright
28 * holders shall not be used in advertising or otherwise to promote the
29 * sale, use or other dealings in this Software without prior written
30 * authorization.
31 */
32
33 #include <xtermcap.h>
34 #include <data.h>
35
36 #include <X11/keysym.h>
37 #include <ctype.h>
38
39 #ifdef VMS
40 #include <X11/keysymdef.h>
41 #endif
42
43 #include <xstrings.h>
44
45 #if USE_TERMINFO && defined(NCURSES_VERSION) && defined(HAVE_USE_EXTENDED_NAMES)
46 #define USE_EXTENDED_NAMES 1
47 #else
48 #define USE_EXTENDED_NAMES 0
49 #endif
50
51 #if USE_TERMINFO
52 #define TcapInit(buffer, name) (setupterm(name, fileno(stdout), &ignored) == OK)
53 #define TcapFree() (del_curterm(cur_term))
54 #else
55 #define TcapInit(buffer, name) (tgetent(buffer, name) == 1)
56 #define TcapFree() /*nothing */
57 #endif
58
59 #define NO_STRING (char *)(-1)
60
61 #if OPT_TCAP_QUERY || OPT_TCAP_FKEYS
62
63 #define SHIFT (MOD_NONE + MOD_SHIFT)
64
65 typedef struct {
66 const char *tc;
67 const char *ti;
68 int code;
69 unsigned param; /* see xtermStateToParam() */
70 } TCAPINFO;
71 /* *INDENT-OFF* */
72 #define DATA(tc,ti,x,y) { tc, ti, x, y }
73 static const TCAPINFO table[] = {
74 /* tcap terminfo code state */
75 DATA( "%1", "khlp", XK_Help, 0 ),
76 DATA( "#1", "kHLP", XK_Help, SHIFT ),
77 DATA( "@0", "kfnd", XK_Find, 0 ),
78 DATA( "*0", "kFND", XK_Find, SHIFT ),
79 DATA( "*6", "kslt", XK_Select, 0 ),
80 DATA( "#6", "kSLT", XK_Select, SHIFT ),
81
82 DATA( "kh", "khome", XK_Home, 0 ),
83 DATA( "#2", "kHOM", XK_Home, SHIFT ),
84 DATA( "@7", "kend", XK_End, 0 ),
85 DATA( "*7", "kEND", XK_End, SHIFT ),
86
87 DATA( "kl", "kcub1", XK_Left, 0 ),
88 DATA( "kr", "kcuf1", XK_Right, 0 ),
89 DATA( "ku", "kcuu1", XK_Up, 0 ),
90 DATA( "kd", "kcud1", XK_Down, 0 ),
91
92 DATA( "#4", "kLFT", XK_Left, SHIFT ),
93 DATA( "%i", "kRIT", XK_Right, SHIFT ),
94 DATA( "kF", "kind", XK_Down, SHIFT ),
95 DATA( "kR", "kri", XK_Up, SHIFT ),
96
97 DATA( "k1", "kf1", XK_Fn(1), 0 ),
98 DATA( "k2", "kf2", XK_Fn(2), 0 ),
99 DATA( "k3", "kf3", XK_Fn(3), 0 ),
100 DATA( "k4", "kf4", XK_Fn(4), 0 ),
101 DATA( "k5", "kf5", XK_Fn(5), 0 ),
102 DATA( "k6", "kf6", XK_Fn(6), 0 ),
103 DATA( "k7", "kf7", XK_Fn(7), 0 ),
104 DATA( "k8", "kf8", XK_Fn(8), 0 ),
105 DATA( "k9", "kf9", XK_Fn(9), 0 ),
106 DATA( "k;", "kf10", XK_Fn(10), 0 ),
107
108 DATA( "F1", "kf11", XK_Fn(11), 0 ),
109 DATA( "F2", "kf12", XK_Fn(12), 0 ),
110 DATA( "F3", "kf13", XK_Fn(13), 0 ),
111 DATA( "F4", "kf14", XK_Fn(14), 0 ),
112 DATA( "F5", "kf15", XK_Fn(15), 0 ),
113 DATA( "F6", "kf16", XK_Fn(16), 0 ),
114 DATA( "F7", "kf17", XK_Fn(17), 0 ),
115 DATA( "F8", "kf18", XK_Fn(18), 0 ),
116 DATA( "F9", "kf19", XK_Fn(19), 0 ),
117 DATA( "FA", "kf20", XK_Fn(20), 0 ),
118 DATA( "FB", "kf21", XK_Fn(21), 0 ),
119 DATA( "FC", "kf22", XK_Fn(22), 0 ),
120 DATA( "FD", "kf23", XK_Fn(23), 0 ),
121 DATA( "FE", "kf24", XK_Fn(24), 0 ),
122 DATA( "FF", "kf25", XK_Fn(25), 0 ),
123 DATA( "FG", "kf26", XK_Fn(26), 0 ),
124 DATA( "FH", "kf27", XK_Fn(27), 0 ),
125 DATA( "FI", "kf28", XK_Fn(28), 0 ),
126 DATA( "FJ", "kf29", XK_Fn(29), 0 ),
127 DATA( "FK", "kf30", XK_Fn(30), 0 ),
128 DATA( "FL", "kf31", XK_Fn(31), 0 ),
129 DATA( "FM", "kf32", XK_Fn(32), 0 ),
130 DATA( "FN", "kf33", XK_Fn(33), 0 ),
131 DATA( "FO", "kf34", XK_Fn(34), 0 ),
132 DATA( "FP", "kf35", XK_Fn(35), 0 ),
133
134 DATA( "FQ", "kf36", -36, 0 ),
135 DATA( "FR", "kf37", -37, 0 ),
136 DATA( "FS", "kf38", -38, 0 ),
137 DATA( "FT", "kf39", -39, 0 ),
138 DATA( "FU", "kf40", -40, 0 ),
139 DATA( "FV", "kf41", -41, 0 ),
140 DATA( "FW", "kf42", -42, 0 ),
141 DATA( "FX", "kf43", -43, 0 ),
142 DATA( "FY", "kf44", -44, 0 ),
143 DATA( "FZ", "kf45", -45, 0 ),
144 DATA( "Fa", "kf46", -46, 0 ),
145 DATA( "Fb", "kf47", -47, 0 ),
146 DATA( "Fc", "kf48", -48, 0 ),
147 DATA( "Fd", "kf49", -49, 0 ),
148 DATA( "Fe", "kf50", -50, 0 ),
149 DATA( "Ff", "kf51", -51, 0 ),
150 DATA( "Fg", "kf52", -52, 0 ),
151 DATA( "Fh", "kf53", -53, 0 ),
152 DATA( "Fi", "kf54", -54, 0 ),
153 DATA( "Fj", "kf55", -55, 0 ),
154 DATA( "Fk", "kf56", -56, 0 ),
155 DATA( "Fl", "kf57", -57, 0 ),
156 DATA( "Fm", "kf58", -58, 0 ),
157 DATA( "Fn", "kf59", -59, 0 ),
158 DATA( "Fo", "kf60", -60, 0 ),
159 DATA( "Fp", "kf61", -61, 0 ),
160 DATA( "Fq", "kf62", -62, 0 ),
161 DATA( "Fr", "kf63", -63, 0 ),
162
163 DATA( "K1", "ka1", XK_KP_Home, 0 ),
164 DATA( "K4", "kc1", XK_KP_End, 0 ),
165 DATA( "K3", "ka3", XK_KP_Prior, 0 ),
166 DATA( "K5", "kc3", XK_KP_Next, 0 ),
167
168 #ifdef XK_ISO_Left_Tab
169 DATA( "kB", "kcbt", XK_ISO_Left_Tab, 0 ),
170 #endif
171 DATA( "kC", "kclr", XK_Clear, 0 ),
172 DATA( "kD", "kdch1", XK_Delete, 0 ),
173 DATA( "kI", "kich1", XK_Insert, 0 ),
174
175 DATA( "kN", "knp", XK_Next, 0 ),
176 DATA( "kP", "kpp", XK_Prior, 0 ),
177 DATA( "%c", "kNXT", XK_Next, SHIFT ),
178 DATA( "%e", "kPRV", XK_Prior, SHIFT ),
179
180 DATA( "&8", "kund", XK_Undo, 0 ),
181 DATA( "kb", "kbs", XK_BackSpace, 0 ),
182 # if OPT_TCAP_QUERY && OPT_ISO_COLORS
183 /* XK_COLORS is a fake code. */
184 DATA( "Co", "colors", XK_COLORS, 0 ),
185 # if OPT_DIRECT_COLOR
186 /* note - termcap cannot support RGB */
187 DATA( "Co", "RGB", XK_RGB, 0 ),
188
189 # endif
190 # endif
191 DATA( "TN", "name", XK_TCAPNAME, 0 ),
192 #if USE_EXTENDED_NAMES
193 #define DEXT(name, parm, code) DATA("", name, code, parm)
194 #define D1ST(name, parm, code) DEXT("k" #name, parm, code)
195 #define DMOD(name, parm, code) DEXT("k" #name #parm, parm, code)
196
197 #define DGRP(name, code) \
198 D1ST(name, 2, code), \
199 DMOD(name, 3, code), \
200 DMOD(name, 4, code), \
201 DMOD(name, 5, code), \
202 DMOD(name, 6, code), \
203 DMOD(name, 7, code), \
204 DMOD(name, 8, code)
205
206 /* the terminfo codes here are ncurses extensions */
207 /* ignore the termcap names, which are empty */
208 DATA( "", "kUP", XK_Up, SHIFT ),
209 DATA( "", "kDN", XK_Up, SHIFT ),
210
211 DGRP(DN, XK_Down),
212 DGRP(LFT, XK_Left),
213 DGRP(RIT, XK_Right),
214 DGRP(UP, XK_Up),
215 DGRP(DC, XK_Delete),
216 DGRP(END, XK_End),
217 DGRP(HOM, XK_Home),
218 DGRP(IC, XK_Insert),
219 DGRP(NXT, XK_Next),
220 DGRP(PRV, XK_Prior),
221 #endif
222 };
223 #undef DATA
224 /* *INDENT-ON* */
225
226 #if OPT_TCAP_FKEYS
227 static Boolean
228 loadTermcapStrings(TScreen *screen)
229 {
230 Boolean result = True;
231
232 if (screen->tcap_fkeys == 0) {
233 Cardinal want = XtNumber(table);
234 Cardinal have;
235 #if !USE_TERMINFO
236 char *area = screen->tcap_area;
237 #endif
238
239 TRACE(("loadTermcapStrings\n"));
240 if ((screen->tcap_fkeys = TypeCallocN(char *, want)) != 0) {
241
242 for (have = 0; have < want; ++have) {
243 char name[80];
244 char *fkey;
245
246 #if USE_TERMINFO
247 fkey = tigetstr(strcpy(name, table[have].ti));
248 #else
249 fkey = tgetstr(strcpy(name, table[have].tc), &area);
250 #endif
251 if (fkey != 0 && fkey != NO_STRING) {
252 screen->tcap_fkeys[have] = x_strdup(fkey);
253 } else {
254 screen->tcap_fkeys[have] = NO_STRING;
255 }
256 }
257 } else {
258 result = False;
259 }
260 }
261 return result;
262 }
263 #endif
264
265 #if OPT_TCAP_QUERY
266 static Boolean
267 keyIsDistinct(XtermWidget xw, int which)
268 {
269 Boolean result = True;
270
271 switch (xw->keyboard.type) {
272 case keyboardIsTermcap:
273 #if OPT_TCAP_FKEYS
274 if (table[which].param == SHIFT) {
275 TScreen *screen = TScreenOf(xw);
276 Cardinal k;
277
278 if (loadTermcapStrings(screen)
279 && screen->tcap_fkeys[which] != NO_STRING) {
280
281 for (k = 0; k < XtNumber(table); k++) {
282
283 if (table[k].code == table[which].code
284 && table[k].param == 0) {
285 char *fkey;
286
287 if ((fkey = screen->tcap_fkeys[k]) != NO_STRING
288 && !strcmp(fkey, screen->tcap_fkeys[which])) {
289 TRACE(("shifted/unshifted keys do not differ\n"));
290 result = False;
291 }
292 break;
293 }
294 }
295 } else {
296 /* there is no data for the shifted key */
297 result = False;
298 }
299 }
300 #endif
301 break;
302 /*
303 * The vt220-keyboard will not return distinct key sequences for
304 * shifted cursor-keys. Just pretend they do not exist, since some
305 * programs may be confused if we return the same data for
306 * shifted/unshifted keys.
307 */
308 case keyboardIsVT220:
309 if (table[which].param == SHIFT) {
310 TRACE(("shifted/unshifted keys do not differ\n"));
311 result = False;
312 }
313 break;
314 case keyboardIsLegacy:
315 case keyboardIsDefault:
316 case keyboardIsHP:
317 case keyboardIsSCO:
318 case keyboardIsSun:
319 break;
320 }
321
322 return result;
323 }
324
325 static int
326 lookupTcapByName(const char *name)
327 {
328 int result = -2;
329 Cardinal j;
330
331 if (!IsEmpty(name)) {
332 for (j = 0; j < XtNumber(table); j++) {
333 if (!strcmp(table[j].ti, name) || !strcmp(table[j].tc, name)) {
334 result = (int) j;
335 break;
336 }
337 }
338 }
339
340 if (result >= 0) {
341 TRACE(("lookupTcapByName(%s) tc=%s, ti=%s code %#x, param %#x\n",
342 name,
343 table[result].tc,
344 table[result].ti,
345 table[result].code,
346 table[result].param));
347 } else {
348 TRACE(("lookupTcapByName(%s) FAIL\n", name));
349 }
350 return result;
351 }
352
353 /*
354 * Parse the termcap/terminfo name from the string, returning a positive number
355 * (the keysym) if found, otherwise -1. Update the string pointer.
356 * Returns the (shift, control) state in *state.
357 *
358 * This does not attempt to construct control/shift modifiers to construct
359 * function-key values. Instead, it sets the *fkey flag to pass to Input()
360 * and bypass the lookup of keysym altogether.
361 */
362 int
363 xtermcapKeycode(XtermWidget xw, const char **params, unsigned *state, Bool *fkey)
364 {
365 const TCAPINFO *data;
366 int code = -1;
367 char *name;
368 const char *p;
369
370 TRACE(("xtermcapKeycode(%s)\n", *params));
371
372 /* Convert hex encoded name to ascii */
373 name = x_decode_hex(*params, &p);
374 *params = p;
375
376 *state = 0;
377 *fkey = False;
378
379 if (!IsEmpty(name) && (*p == 0 || *p == ';')) {
380 int which;
381
382 if ((which = lookupTcapByName(name)) >= 0) {
383 if (keyIsDistinct(xw, which)) {
384 data = table + which;
385 code = data->code;
386 *state = xtermParamToState(xw, data->param);
387 if (IsFunctionKey(code)) {
388 *fkey = True;
389 } else if (code < 0) {
390 *fkey = True;
391 code = XK_Fn((-code));
392 }
393 #if OPT_SUN_FUNC_KEYS
394 if (*fkey && xw->keyboard.type == keyboardIsSun) {
395 int num = code - XK_Fn(0);
396
397 /* match function-key case in sunfuncvalue() */
398 if (num > 20) {
399 if (num <= 30 || num > 47) {
400 code = -1;
401 } else {
402 code -= 10;
403 switch (num) {
404 case 37: /* khome */
405 case 39: /* kpp */
406 case 41: /* kb2 */
407 case 43: /* kend */
408 case 45: /* knp */
409 code = -1;
410 break;
411 }
412 }
413 }
414 }
415 #endif
416 } else {
417 TRACE(("... name ok, data not ok\n"));
418 code = -1;
419 }
420 } else {
421 TRACE(("... name not ok\n"));
422 code = -2;
423 }
424 } else {
425 TRACE(("... name not ok\n"));
426 code = -2;
427 }
428
429 TRACE(("... xtermcapKeycode(%s, %u, %d) -> %#06x\n",
430 name, *state, *fkey, code));
431 free(name);
432 return code;
433 }
434 #endif /* OPT_TCAP_QUERY */
435
436 #if OPT_TCAP_FKEYS
437 static int
438 nextTcapByCode(int code, unsigned param, int last)
439 {
440 int result = -1;
441 int n;
442
443 TRACE(("lookupTcapByCode %#x:%#x\n", code, param));
444 for (n = last + 1; n < (int) XtNumber(table); n++) {
445 if (table[n].code == code &&
446 table[n].param == param) {
447 TRACE(("->lookupTcapByCode %d:%s\n", n, table[n].ti));
448 result = n;
449 break;
450 }
451 }
452 return result;
453 }
454
455 static int
456 firstTcapByCode(int code, unsigned param)
457 {
458 return nextTcapByCode(code, param, -1);
459 }
460
461 int
462 xtermcapString(XtermWidget xw, int keycode, unsigned mask)
463 {
464 int result = 0;
465 unsigned param = xtermStateToParam(xw, mask);
466 int which;
467
468 if ((which = firstTcapByCode(keycode, param)) >= 0) {
469 TScreen *screen = TScreenOf(xw);
470
471 if (loadTermcapStrings(screen)) {
472 do {
473 char *fkey;
474
475 if ((fkey = screen->tcap_fkeys[which]) != NO_STRING) {
476 StringInput(xw, (Char *) fkey, strlen(fkey));
477 result = 1;
478 break;
479 }
480 } while ((which = nextTcapByCode(keycode, param, which)) >= 0);
481 }
482 }
483
484 TRACE(("xtermcapString(keycode=%#x, mask=%#x) ->%d\n",
485 keycode, mask, result));
486
487 return result;
488 }
489 #endif /* OPT_TCAP_FKEYS */
490
491 #endif /* OPT_TCAP_QUERY || OPT_TCAP_FKEYS */
492
493 /*
494 * If we're linked to terminfo, tgetent() will return an empty buffer. We
495 * cannot use that to adjust the $TERMCAP variable.
496 */
497 Bool
498 get_termcap(XtermWidget xw, char *name)
499 {
500 #if USE_TERMINFO
501 int ignored = 0;
502 #endif
503 char *buffer = get_tcap_buffer(xw);
504
505 *buffer = 0; /* initialize, in case we're using terminfo's tgetent */
506
507 #if USE_EXTENDED_NAMES
508 use_extended_names(TRUE);
509 #endif
510 if (!IsEmpty(name)) {
511 if (TcapInit(buffer, name)) {
512 TRACE(("get_termcap(%s) succeeded (%s)\n", name,
513 (*buffer
514 ? "ok:termcap, we can update $TERMCAP"
515 : "assuming this is terminfo")));
516 return True;
517 } else {
518 *buffer = 0; /* just in case */
519 }
520 }
521 return False;
522 }
523
524 /*
525 * Retrieve the termcap-buffer.
526 */
527 char *
528 get_tcap_buffer(XtermWidget xw)
529 {
530 TScreen *screen = TScreenOf(xw);
531 char *buffer;
532
533 #if OPT_TEK4014
534 if (TEK4014_ACTIVE(xw)) {
535 buffer = TekScreenOf(tekWidget)->tcapbuf;
536 } else
537 #endif
538 {
539 buffer = screen->tcapbuf;
540 }
541 return buffer;
542 }
543
544 /*
545 * Retrieve the erase-key, for initialization in main program.
546 */
547 char *
548 get_tcap_erase(XtermWidget xw)
549 {
550 #if !USE_TERMINFO
551 char *area = TScreenOf(xw)->tcap_area;
552 #endif
553 char *fkey;
554
555 (void) xw;
556 #if USE_TERMINFO
557 fkey = tigetstr("kbs");
558 #else
559 fkey = tgetstr("kb", &area);
560 #endif
561
562 if (fkey == NO_STRING)
563 fkey = 0;
564 if (fkey != 0)
565 fkey = x_strdup(fkey);
566 return fkey;
567 }
568
569 /*
570 * A legal termcap (or terminfo) name consists solely of graphic characters,
571 * excluding the punctuation used to delimit fields of the source description.
572 */
573 static Bool
574 isLegalTcapName(const char *name)
575 {
576 Bool result = False;
577
578 if (*name != '\0') {
579 int length = 0;
580 result = True;
581 while (*name != '\0') {
582 if (++length < 32 && isgraph(CharOf(*name))) {
583 if (strchr("\\|,:'\"", *name) != 0) {
584 result = False;
585 break;
586 }
587 } else {
588 result = False;
589 break;
590 }
591 ++name;
592 }
593 }
594
595 return result;
596 }
597
598 void
599 set_termcap(XtermWidget xw, const char *name)
600 {
601 Boolean success = False;
602 #if USE_TERMINFO
603 int ignored = 0;
604 #else
605 TScreen *screen = TScreenOf(xw);
606 char buffer[sizeof(screen->tcapbuf)];
607 #endif
608
609 TRACE(("set_termcap(%s)\n", NonNull(name)));
610 if (IsEmpty(name)) {
611 Bell(xw, XkbBI_MinorError, 0);
612 } else {
613 const char *temp;
614 char *value;
615
616 if ((value = x_decode_hex(name, &temp)) != 0) {
617 if (*temp == '\0' && isLegalTcapName(value)) {
618 if (TcapInit(buffer, value)) {
619 TRACE(("...set_termcap(%s)\n", NonNull(value)));
620 #if !USE_TERMINFO
621 memcpy(screen->tcapbuf, buffer, sizeof(buffer));
622 #endif
623 free_termcap(xw);
624 success = True;
625 }
626 }
627 free(value);
628 }
629 }
630 if (!success)
631 Bell(xw, XkbBI_MinorError, 0);
632 }
633
634 void
635 free_termcap(XtermWidget xw)
636 {
637 #if OPT_TCAP_FKEYS
638 TScreen *screen = TScreenOf(xw);
639
640 if (screen->tcap_fkeys != 0) {
641 Cardinal want = XtNumber(table);
642 Cardinal have;
643
644 for (have = 0; have < want; ++have) {
645 char *fkey = screen->tcap_fkeys[have];
646 if (fkey != NO_STRING) {
647 free(fkey);
648 }
649 }
650 FreeAndNull(screen->tcap_fkeys);
651 }
652 #endif
653 TcapFree();
654 }