📄 tic.c
字号:
if (keypad_index(key_b2) >= 0) strcat(show, " kb2"); if (keypad_index(key_c1) >= 0) strcat(show, " kc1"); if (keypad_index(key_c3) >= 0) strcat(show, " kc3"); if (*show != '\0') _nc_warning("vt100 keypad map incomplete:%s", show); }}/* * Returns the expected number of parameters for the given capability. */static intexpected_params(const char *name){ /* *INDENT-OFF* */ static const struct { const char *name; int count; } table[] = { { "S0", 1 }, /* 'screen' extension */ { "birep", 2 }, { "chr", 1 }, { "colornm", 1 }, { "cpi", 1 }, { "csnm", 1 }, { "csr", 2 }, { "cub", 1 }, { "cud", 1 }, { "cuf", 1 }, { "cup", 2 }, { "cuu", 1 }, { "cvr", 1 }, { "cwin", 5 }, { "dch", 1 }, { "defc", 3 }, { "dial", 1 }, { "dispc", 1 }, { "dl", 1 }, { "ech", 1 }, { "getm", 1 }, { "hpa", 1 }, { "ich", 1 }, { "il", 1 }, { "indn", 1 }, { "initc", 4 }, { "initp", 7 }, { "lpi", 1 }, { "mc5p", 1 }, { "mrcup", 2 }, { "mvpa", 1 }, { "pfkey", 2 }, { "pfloc", 2 }, { "pfx", 2 }, { "pfxl", 3 }, { "pln", 2 }, { "qdial", 1 }, { "rcsd", 1 }, { "rep", 2 }, { "rin", 1 }, { "sclk", 3 }, { "scp", 1 }, { "scs", 1 }, { "scsd", 2 }, { "setab", 1 }, { "setaf", 1 }, { "setb", 1 }, { "setcolor", 1 }, { "setf", 1 }, { "sgr", 9 }, { "sgr1", 6 }, { "slength", 1 }, { "slines", 1 }, { "smgbp", 1 }, /* 2 if smgtp is not given */ { "smglp", 1 }, { "smglr", 2 }, { "smgrp", 1 }, { "smgtb", 2 }, { "smgtp", 1 }, { "tsl", 1 }, { "u6", -1 }, { "vpa", 1 }, { "wind", 4 }, { "wingo", 1 }, }; /* *INDENT-ON* */ unsigned n; int result = 0; /* function-keys, etc., use none */ for (n = 0; n < SIZEOF(table); n++) { if (!strcmp(name, table[n].name)) { result = table[n].count; break; } } return result;}/* * Make a quick sanity check for the parameters which are used in the given * strings. If there are no "%p" tokens, then there should be no other "%" * markers. */static voidcheck_params(TERMTYPE *tp, const char *name, char *value){ int expected = expected_params(name); int actual = 0; int n; bool params[10]; char *s = value;#ifdef set_top_margin_parm if (!strcmp(name, "smgbp") && set_top_margin_parm == 0) expected = 2;#endif for (n = 0; n < 10; n++) params[n] = FALSE; while (*s != 0) { if (*s == '%') { if (*++s == '\0') { _nc_warning("expected character after %% in %s", name); break; } else if (*s == 'p') { if (*++s == '\0' || !isdigit((int) *s)) { _nc_warning("expected digit after %%p in %s", name); return; } else { n = (*s - '0'); if (n > actual) actual = n; params[n] = TRUE; } } } s++; } if (params[0]) { _nc_warning("%s refers to parameter 0 (%%p0), which is not allowed", name); } if (value == set_attributes || expected < 0) { ; } else if (expected != actual) { _nc_warning("%s uses %d parameters, expected %d", name, actual, expected); for (n = 1; n < actual; n++) { if (!params[n]) _nc_warning("%s omits parameter %d", name, n); } }}static char *skip_delay(char *s){ while (*s == '/' || isdigit(UChar(*s))) ++s; return s;}/* * Skip a delay altogether, e.g., when comparing a simple string to sgr, * the latter may have a worst-case delay on the end. */static char *ignore_delays(char *s){ int delaying = 0; do { switch (*s) { case '$': if (delaying == 0) delaying = 1; break; case '<': if (delaying == 1) delaying = 2; break; case '\0': delaying = 0; break; default: if (delaying) { s = skip_delay(s); if (*s == '>') ++s; delaying = 0; } break; } if (delaying) ++s; } while (delaying); return s;}/* * An sgr string may contain several settings other than the one we're * interested in, essentially sgr0 + rmacs + whatever. As long as the * "whatever" is contained in the sgr string, that is close enough for our * sanity check. */static boolsimilar_sgr(int num, char *a, char *b){ static const char *names[] = { "none" ,"standout" ,"underline" ,"reverse" ,"blink" ,"dim" ,"bold" ,"invis" ,"protect" ,"altcharset" }; char *base_a = a; char *base_b = b; int delaying = 0; while (*b != 0) { while (*a != *b) { if (*a == 0) { if (b[0] == '$' && b[1] == '<') { _nc_warning("Did not find delay %s", _nc_visbuf(b)); } else { _nc_warning("checking sgr(%s) %s\n\tcompare to %s\n\tunmatched %s", names[num], _nc_visbuf2(1, base_a), _nc_visbuf2(2, base_b), _nc_visbuf2(3, b)); } return FALSE; } else if (delaying) { a = skip_delay(a); b = skip_delay(b); } else { a++; } } switch (*a) { case '$': if (delaying == 0) delaying = 1; break; case '<': if (delaying == 1) delaying = 2; break; default: delaying = 0; break; } a++; b++; } /* ignore delays on the end of the string */ a = ignore_delays(a); return ((num != 0) || (*a == 0));}static char *check_sgr(TERMTYPE *tp, char *zero, int num, char *cap, const char *name){ char *test; _nc_tparm_err = 0; test = tparm(set_attributes, num == 1, num == 2, num == 3, num == 4, num == 5, num == 6, num == 7, num == 8, num == 9); if (test != 0) { if (PRESENT(cap)) { if (!similar_sgr(num, test, cap)) { _nc_warning("%s differs from sgr(%d)\n\t%s=%s\n\tsgr(%d)=%s", name, num, name, _nc_visbuf2(1, cap), num, _nc_visbuf2(2, test)); } } else if (_nc_capcmp(test, zero)) { _nc_warning("sgr(%d) present, but not %s", num, name); } } else if (PRESENT(cap)) { _nc_warning("sgr(%d) missing, but %s present", num, name); } if (_nc_tparm_err) _nc_warning("stack error in sgr(%d) string", num); return test;}#define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name)#ifdef TRACE/* * If tic is compiled with TRACE, we'll be able to see the output from the * DEBUG() macro. But since it doesn't use traceon(), it always goes to * the standard error. Use this function to make it simpler to follow the * resulting debug traces. */static voidshow_where(unsigned level){ if (_nc_tracing >= level) { char my_name[256]; _nc_get_type(my_name); fprintf(stderr, "\"%s\", line %d, '%s' ", _nc_get_source(), _nc_curr_line, my_name); }}#else#define show_where(level) /* nothing */#endif/* other sanity-checks (things that we don't want in the normal * logic that reads a terminfo entry) */static voidcheck_termtype(TERMTYPE *tp, bool literal){ bool conflict = FALSE; unsigned j, k; char fkeys[STRCOUNT]; /* * A terminal entry may contain more than one keycode assigned to * a given string (e.g., KEY_END and KEY_LL). But curses will only * return one (the last one assigned). */ if (!(_nc_syntax == SYN_TERMCAP && capdump)) { memset(fkeys, 0, sizeof(fkeys)); for (j = 0; _nc_tinfo_fkeys[j].code; j++) { char *a = tp->Strings[_nc_tinfo_fkeys[j].offset]; bool first = TRUE; if (!VALID_STRING(a)) continue; for (k = j + 1; _nc_tinfo_fkeys[k].code; k++) { char *b = tp->Strings[_nc_tinfo_fkeys[k].offset]; if (!VALID_STRING(b) || fkeys[k]) continue; if (!_nc_capcmp(a, b)) { fkeys[j] = 1; fkeys[k] = 1; if (first) { if (!conflict) { _nc_warning("Conflicting key definitions (using the last)"); conflict = TRUE; } fprintf(stderr, "... %s is the same as %s", keyname((int) _nc_tinfo_fkeys[j].code), keyname((int) _nc_tinfo_fkeys[k].code)); first = FALSE; } else { fprintf(stderr, ", %s", keyname((int) _nc_tinfo_fkeys[k].code)); } } } if (!first) fprintf(stderr, "\n"); } } for (j = 0; j < NUM_STRINGS(tp); j++) { char *a = tp->Strings[j]; if (VALID_STRING(a)) check_params(tp, ExtStrname(tp, j, strnames), a); } check_acs(tp); check_colors(tp); check_keypad(tp); /* * These may be mismatched because the terminal description relies on * restoring the cursor visibility by resetting it. */ ANDMISSING(cursor_invisible, cursor_normal); ANDMISSING(cursor_visible, cursor_normal); if (PRESENT(cursor_visible) && PRESENT(cursor_normal) && !_nc_capcmp(cursor_visible, cursor_normal)) _nc_warning("cursor_visible is same as cursor_normal"); /* * From XSI & O'Reilly, we gather that sc/rc are required if csr is * given, because the cursor position after the scrolling operation is * performed is undefined. */ ANDMISSING(change_scroll_region, save_cursor); ANDMISSING(change_scroll_region, restore_cursor); if (PRESENT(set_attributes)) { char *zero = 0; _nc_tparm_err = 0; if (PRESENT(exit_attribute_mode)) { zero = strdup(CHECK_SGR(0, exit_attribute_mode)); } else { zero = strdup(tparm(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0)); } if (_nc_tparm_err) _nc_warning("stack error in sgr(0) string"); if (zero != 0) { CHECK_SGR(1, enter_standout_mode); CHECK_SGR(2, enter_underline_mode); CHECK_SGR(3, enter_reverse_mode); CHECK_SGR(4, enter_blink_mode); CHECK_SGR(5, enter_dim_mode); CHECK_SGR(6, enter_bold_mode); CHECK_SGR(7, enter_secure_mode); CHECK_SGR(8, enter_protected_mode); CHECK_SGR(9, enter_alt_charset_mode); free(zero); } else { _nc_warning("sgr(0) did not return a value"); } } else if (PRESENT(exit_attribute_mode) && set_attributes != CANCELLED_STRING) { if (_nc_syntax == SYN_TERMINFO) _nc_warning("missing sgr string"); } if (PRESENT(exit_attribute_mode)) { char *check_sgr0 = _nc_trim_sgr0(tp); if (check_sgr0 == 0 || *check_sgr0 == '\0') { _nc_warning("trimmed sgr0 is empty"); } else { show_where(2); if (check_sgr0 != exit_attribute_mode) { DEBUG(2, ("will trim sgr0\n\toriginal sgr0=%s\n\ttrimmed sgr0=%s", _nc_visbuf2(1, exit_attribute_mode), _nc_visbuf2(2, check_sgr0))); free(check_sgr0); } else { DEBUG(2, ("will not trim sgr0\n\toriginal sgr0=%s", _nc_visbuf(exit_attribute_mode))); } } }#ifdef TRACE show_where(2); if (!auto_right_margin) { DEBUG(2, ("can write to lower-right directly")); } else if (PRESENT(enter_am_mode) && PRESENT(exit_am_mode)) { DEBUG(2, ("can write to lower-right by suppressing automargin")); } else if ((PRESENT(enter_insert_mode) && PRESENT(exit_insert_mode)) || PRESENT(insert_character) || PRESENT(parm_ich)) { DEBUG(2, ("can write to lower-right by using inserts")); } else { DEBUG(2, ("cannot write to lower-right")); }#endif /* * Some standard applications (e.g., vi) and some non-curses * applications (e.g., jove) get confused if we have both ich1 and * smir/rmir. Let's be nice and warn about that, too, even though * ncurses handles it. */ if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode)) && PRESENT(parm_ich)) { _nc_warning("non-curses applications may be confused by ich1 with smir/rmir"); } /* * Finally, do the non-verbose checks */ if (save_check_termtype != 0) save_check_termtype(tp, literal);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -