Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 1 | /**************************************************************************** |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 2 | * Copyright 2018-2023,2024 Thomas E. Dickey * |
| 3 | * Copyright 1998-2016,2017 Free Software Foundation, Inc. * |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 4 | * * |
| 5 | * Permission is hereby granted, free of charge, to any person obtaining a * |
| 6 | * copy of this software and associated documentation files (the * |
| 7 | * "Software"), to deal in the Software without restriction, including * |
| 8 | * without limitation the rights to use, copy, modify, merge, publish, * |
| 9 | * distribute, distribute with modifications, sublicense, and/or sell * |
| 10 | * copies of the Software, and to permit persons to whom the Software is * |
| 11 | * furnished to do so, subject to the following conditions: * |
| 12 | * * |
| 13 | * The above copyright notice and this permission notice shall be included * |
| 14 | * in all copies or substantial portions of the Software. * |
| 15 | * * |
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * |
| 17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * |
| 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * |
| 19 | * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * |
| 20 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * |
| 21 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * |
| 22 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * |
| 23 | * * |
| 24 | * Except as contained in this notice, the name(s) of the above copyright * |
| 25 | * holders shall not be used in advertising or otherwise to promote the * |
| 26 | * sale, use or other dealings in this Software without prior written * |
| 27 | * authorization. * |
| 28 | ****************************************************************************/ |
| 29 | |
| 30 | /**************************************************************************** |
| 31 | * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * |
| 32 | * and: Eric S. Raymond <esr@snark.thyrsus.com> * |
| 33 | * and: Thomas E. Dickey 1996-on * |
| 34 | ****************************************************************************/ |
| 35 | |
| 36 | /* |
| 37 | * comp_parse.c -- parser driver loop and use handling. |
| 38 | * |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 39 | * Use this code by calling _nc_read_entry_source() on as many source |
| 40 | * files as you like (either terminfo or termcap syntax). If you |
| 41 | * want use-resolution, call _nc_resolve_uses2(). To free the list |
| 42 | * storage, do _nc_free_entries(). |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 43 | */ |
| 44 | |
| 45 | #include <curses.priv.h> |
| 46 | |
| 47 | #include <ctype.h> |
| 48 | |
| 49 | #include <tic.h> |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 50 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 51 | MODULE_ID("$Id: comp_parse.c,v 1.134 2024/02/10 15:52:11 tom Exp $") |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 52 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 53 | static void sanity_check2(TERMTYPE2 *, bool); |
| 54 | NCURSES_IMPEXP void (NCURSES_API *_nc_check_termtype2) (TERMTYPE2 *, bool) = sanity_check2; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 55 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 56 | static void fixup_acsc(TERMTYPE2 *, int); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 57 | |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 58 | static void |
| 59 | enqueue(ENTRY * ep) |
| 60 | /* add an entry to the in-core list */ |
| 61 | { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 62 | ENTRY *newp; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 63 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 64 | DEBUG(2, (T_CALLED("enqueue(ep=%p)"), (void *) ep)); |
| 65 | |
| 66 | newp = _nc_copy_entry(ep); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 67 | if (newp == 0) |
| 68 | _nc_err_abort(MSG_NO_MEMORY); |
| 69 | |
| 70 | newp->last = _nc_tail; |
| 71 | _nc_tail = newp; |
| 72 | |
| 73 | newp->next = 0; |
| 74 | if (newp->last) |
| 75 | newp->last->next = newp; |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 76 | DEBUG(2, (T_RETURN(""))); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 77 | } |
| 78 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 79 | #define NAMEBUFFER_SIZE (MAX_NAME_SIZE + 2) |
| 80 | |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 81 | static char * |
| 82 | force_bar(char *dst, char *src) |
| 83 | { |
| 84 | if (strchr(src, '|') == 0) { |
| 85 | size_t len = strlen(src); |
| 86 | if (len > MAX_NAME_SIZE) |
| 87 | len = MAX_NAME_SIZE; |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 88 | _nc_STRNCPY(dst, src, MAX_NAME_SIZE); |
| 89 | _nc_STRCPY(dst + len, "|", NAMEBUFFER_SIZE - len); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 90 | src = dst; |
| 91 | } |
| 92 | return src; |
| 93 | } |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 94 | #define ForceBar(dst, src) ((strchr(src, '|') == 0) ? force_bar(dst, src) : src) |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 95 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 96 | #if NCURSES_USE_TERMCAP && NCURSES_XNAMES |
| 97 | static char * |
| 98 | skip_index(char *name) |
| 99 | { |
| 100 | char *bar = strchr(name, '|'); |
| 101 | |
| 102 | if (bar != 0 && (bar - name) == 2) |
| 103 | name = bar + 1; |
| 104 | |
| 105 | return name; |
| 106 | } |
| 107 | #endif |
| 108 | |
| 109 | static bool |
| 110 | check_collisions(char *n1, char *n2, int counter) |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 111 | { |
| 112 | char *pstart, *qstart, *pend, *qend; |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 113 | char nc1[NAMEBUFFER_SIZE]; |
| 114 | char nc2[NAMEBUFFER_SIZE]; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 115 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 116 | n1 = ForceBar(nc1, n1); |
| 117 | n2 = ForceBar(nc2, n2); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 118 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 119 | #if NCURSES_USE_TERMCAP && NCURSES_XNAMES |
| 120 | if ((_nc_syntax == SYN_TERMCAP) && _nc_user_definable) { |
| 121 | n1 = skip_index(n1); |
| 122 | n2 = skip_index(n2); |
| 123 | } |
| 124 | #endif |
| 125 | |
| 126 | for (pstart = n1; (pend = strchr(pstart, '|')); pstart = pend + 1) { |
| 127 | for (qstart = n2; (qend = strchr(qstart, '|')); qstart = qend + 1) { |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 128 | if ((pend - pstart == qend - qstart) |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 129 | && memcmp(pstart, qstart, (size_t) (pend - pstart)) == 0) { |
| 130 | if (counter > 0) |
| 131 | (void) fprintf(stderr, "Name collision '%.*s' between\n", |
| 132 | (int) (pend - pstart), pstart); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 133 | return (TRUE); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 134 | } |
| 135 | } |
| 136 | } |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 137 | |
| 138 | return (FALSE); |
| 139 | } |
| 140 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 141 | static char * |
| 142 | next_name(char *name) |
| 143 | { |
| 144 | if (*name != '\0') |
| 145 | ++name; |
| 146 | return name; |
| 147 | } |
| 148 | |
| 149 | static char * |
| 150 | name_ending(char *name) |
| 151 | { |
| 152 | if (*name == '\0') { |
| 153 | name = 0; |
| 154 | } else { |
| 155 | while (*name != '\0' && *name != '|') |
| 156 | ++name; |
| 157 | } |
| 158 | return name; |
| 159 | } |
| 160 | |
| 161 | /* |
| 162 | * Essentially, find the conflict reported in check_collisions() and remove |
| 163 | * it from the second name, unless that happens to be the last alias. |
| 164 | */ |
| 165 | static bool |
| 166 | remove_collision(char *n1, char *n2) |
| 167 | { |
| 168 | char *p2 = n2; |
| 169 | char *pstart, *qstart, *pend, *qend; |
| 170 | bool removed = FALSE; |
| 171 | |
| 172 | #if NCURSES_USE_TERMCAP && NCURSES_XNAMES |
| 173 | if ((_nc_syntax == SYN_TERMCAP) && _nc_user_definable) { |
| 174 | n1 = skip_index(n1); |
| 175 | p2 = n2 = skip_index(n2); |
| 176 | } |
| 177 | #endif |
| 178 | |
| 179 | for (pstart = n1; (pend = name_ending(pstart)); pstart = next_name(pend)) { |
| 180 | for (qstart = n2; (qend = name_ending(qstart)); qstart = next_name(qend)) { |
| 181 | if ((pend - pstart == qend - qstart) |
| 182 | && memcmp(pstart, qstart, (size_t) (pend - pstart)) == 0) { |
| 183 | if (qstart != p2 || *qend == '|') { |
| 184 | if (*qend == '|') |
| 185 | ++qend; |
| 186 | while ((*qstart++ = *qend++) != '\0') ; |
| 187 | fprintf(stderr, "...now\t%s\n", p2); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 188 | removed = TRUE; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 189 | } else { |
| 190 | fprintf(stderr, "Cannot remove alias '%.*s'\n", |
| 191 | (int) (qend - qstart), qstart); |
| 192 | } |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 193 | break; |
| 194 | } |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | return removed; |
| 199 | } |
| 200 | |
| 201 | /* do any of the aliases in a pair of terminal names match? */ |
| 202 | NCURSES_EXPORT(bool) |
| 203 | _nc_entry_match(char *n1, char *n2) |
| 204 | { |
| 205 | return check_collisions(n1, n2, 0); |
| 206 | } |
| 207 | |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 208 | /**************************************************************************** |
| 209 | * |
| 210 | * Entry compiler and resolution logic |
| 211 | * |
| 212 | ****************************************************************************/ |
| 213 | |
| 214 | NCURSES_EXPORT(void) |
| 215 | _nc_read_entry_source(FILE *fp, char *buf, |
| 216 | int literal, bool silent, |
| 217 | bool(*hook) (ENTRY *)) |
| 218 | /* slurp all entries in the given file into core */ |
| 219 | { |
| 220 | ENTRY thisentry; |
| 221 | bool oldsuppress = _nc_suppress_warnings; |
| 222 | int immediate = 0; |
| 223 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 224 | DEBUG(2, |
| 225 | (T_CALLED("_nc_read_entry_source(" |
| 226 | "file=%p, buf=%p, literal=%d, silent=%d, hook=%#" |
| 227 | PRIxPTR ")"), |
| 228 | (void *) fp, buf, literal, silent, CASTxPTR(hook))); |
| 229 | |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 230 | if (silent) |
| 231 | _nc_suppress_warnings = TRUE; /* shut the lexer up, too */ |
| 232 | |
| 233 | _nc_reset_input(fp, buf); |
| 234 | for (;;) { |
| 235 | memset(&thisentry, 0, sizeof(thisentry)); |
| 236 | if (_nc_parse_entry(&thisentry, literal, silent) == ERR) |
| 237 | break; |
| 238 | if (!isalnum(UChar(thisentry.tterm.term_names[0]))) |
| 239 | _nc_err_abort("terminal names must start with letter or digit"); |
| 240 | |
| 241 | /* |
| 242 | * This can be used for immediate compilation of entries with no "use=" |
| 243 | * references to disk. That avoids consuming a lot of memory when the |
| 244 | * resolution code could fetch entries off disk. |
| 245 | */ |
| 246 | if (hook != NULLHOOK && (*hook) (&thisentry)) { |
| 247 | immediate++; |
| 248 | } else { |
| 249 | enqueue(&thisentry); |
| 250 | /* |
| 251 | * The enqueued entry is copied with _nc_copy_termtype(), so we can |
| 252 | * free some of the data from thisentry, i.e., the arrays. |
| 253 | */ |
| 254 | FreeIfNeeded(thisentry.tterm.Booleans); |
| 255 | FreeIfNeeded(thisentry.tterm.Numbers); |
| 256 | FreeIfNeeded(thisentry.tterm.Strings); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 257 | FreeIfNeeded(thisentry.tterm.str_table); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 258 | #if NCURSES_XNAMES |
| 259 | FreeIfNeeded(thisentry.tterm.ext_Names); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 260 | FreeIfNeeded(thisentry.tterm.ext_str_table); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 261 | #endif |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | if (_nc_tail) { |
| 266 | /* set up the head pointer */ |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 267 | for (_nc_head = _nc_tail; _nc_head->last; _nc_head = _nc_head->last) { |
| 268 | /* EMPTY */ ; |
| 269 | } |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 270 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 271 | DEBUG(2, ("head = %s", _nc_head->tterm.term_names)); |
| 272 | DEBUG(2, ("tail = %s", _nc_tail->tterm.term_names)); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 273 | } |
| 274 | #ifdef TRACE |
| 275 | else if (!immediate) |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 276 | DEBUG(2, ("no entries parsed")); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 277 | #endif |
| 278 | |
| 279 | _nc_suppress_warnings = oldsuppress; |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 280 | DEBUG(2, (T_RETURN(""))); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 281 | } |
| 282 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 283 | #if 0 && NCURSES_XNAMES |
| 284 | static unsigned |
| 285 | find_capname(TERMTYPE2 *p, const char *name) |
| 286 | { |
| 287 | unsigned num_names = NUM_EXT_NAMES(p); |
| 288 | unsigned n; |
| 289 | if (name != 0) { |
| 290 | for (n = 0; n < num_names; ++n) { |
| 291 | if (!strcmp(p->ext_Names[n], name)) |
| 292 | break; |
| 293 | } |
| 294 | } else { |
| 295 | n = num_names + 1; |
| 296 | } |
| 297 | return n; |
| 298 | } |
| 299 | |
| 300 | static int |
| 301 | extended_captype(TERMTYPE2 *p, unsigned which) |
| 302 | { |
| 303 | int result = UNDEF; |
| 304 | unsigned limit = 0; |
| 305 | limit += p->ext_Booleans; |
| 306 | if (limit != 0 && which < limit) { |
| 307 | result = BOOLEAN; |
| 308 | } else { |
| 309 | limit += p->ext_Numbers; |
| 310 | if (limit != 0 && which < limit) { |
| 311 | result = NUMBER; |
| 312 | } else { |
| 313 | limit += p->ext_Strings; |
| 314 | if (limit != 0 && which < limit) { |
| 315 | result = ((p->Strings[STRCOUNT + which] != CANCELLED_STRING) |
| 316 | ? STRING |
| 317 | : CANCEL); |
| 318 | } else if (which >= limit) { |
| 319 | result = CANCEL; |
| 320 | } |
| 321 | } |
| 322 | } |
| 323 | return result; |
| 324 | } |
| 325 | |
| 326 | static const char * |
| 327 | name_of_captype(int which) |
| 328 | { |
| 329 | const char *result = "?"; |
| 330 | switch (which) { |
| 331 | case BOOLEAN: |
| 332 | result = "boolean"; |
| 333 | break; |
| 334 | case NUMBER: |
| 335 | result = "number"; |
| 336 | break; |
| 337 | case STRING: |
| 338 | result = "string"; |
| 339 | break; |
| 340 | } |
| 341 | return result; |
| 342 | } |
| 343 | |
| 344 | #define valid_TERMTYPE2(p) \ |
| 345 | ((p) != 0 && \ |
| 346 | (p)->term_names != 0 && \ |
| 347 | (p)->ext_Names != 0) |
| 348 | |
| 349 | /* |
| 350 | * Disallow changing the type of an extended capability when doing a "use" |
| 351 | * if one or the other is a string. |
| 352 | */ |
| 353 | static int |
| 354 | invalid_merge(TERMTYPE2 *to, TERMTYPE2 *from) |
| 355 | { |
| 356 | int rc = FALSE; |
| 357 | if (valid_TERMTYPE2(to) |
| 358 | && valid_TERMTYPE2(from)) { |
| 359 | char *to_name = _nc_first_name(to->term_names); |
| 360 | char *from_name = strdup(_nc_first_name(from->term_names)); |
| 361 | unsigned num_names = NUM_EXT_NAMES(from); |
| 362 | unsigned n; |
| 363 | |
| 364 | for (n = 0; n < num_names; ++n) { |
| 365 | const char *capname = from->ext_Names[n]; |
| 366 | int tt = extended_captype(to, find_capname(to, capname)); |
| 367 | int tf = extended_captype(from, n); |
| 368 | |
| 369 | if (tt <= STRING |
| 370 | && tf <= STRING |
| 371 | && (tt == STRING) != (tf == STRING)) { |
| 372 | if (from_name != 0 && strcmp(to_name, from_name)) { |
| 373 | _nc_warning("merge of %s to %s changes type of %s from %s to %s", |
| 374 | from_name, |
| 375 | to_name, |
| 376 | from->ext_Names[n], |
| 377 | name_of_captype(tf), |
| 378 | name_of_captype(tt)); |
| 379 | } else { |
| 380 | _nc_warning("merge of %s changes type of %s from %s to %s", |
| 381 | to_name, |
| 382 | from->ext_Names[n], |
| 383 | name_of_captype(tf), |
| 384 | name_of_captype(tt)); |
| 385 | } |
| 386 | rc = TRUE; |
| 387 | } |
| 388 | } |
| 389 | free(from_name); |
| 390 | } |
| 391 | return rc; |
| 392 | } |
| 393 | #define validate_merge(p, q) \ |
| 394 | if (invalid_merge(&((p)->tterm), &((q)->tterm))) \ |
| 395 | return FALSE |
| 396 | #else |
| 397 | #define validate_merge(p, q) /* nothing */ |
| 398 | #endif |
| 399 | |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 400 | NCURSES_EXPORT(int) |
| 401 | _nc_resolve_uses2(bool fullresolve, bool literal) |
| 402 | /* try to resolve all use capabilities */ |
| 403 | { |
| 404 | ENTRY *qp, *rp, *lastread = 0; |
| 405 | bool keepgoing; |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 406 | unsigned i, j; |
| 407 | int total_unresolved, multiples; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 408 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 409 | DEBUG(2, (T_CALLED("_nc_resolve_uses2"))); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 410 | |
| 411 | /* |
| 412 | * Check for multiple occurrences of the same name. |
| 413 | */ |
| 414 | multiples = 0; |
| 415 | for_entry_list(qp) { |
| 416 | int matchcount = 0; |
| 417 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 418 | for_entry_list2(rp, qp->next) { |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 419 | if (qp > rp |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 420 | && check_collisions(qp->tterm.term_names, |
| 421 | rp->tterm.term_names, |
| 422 | matchcount + 1)) { |
| 423 | if (!matchcount++) { |
| 424 | (void) fprintf(stderr, "\t%s\n", rp->tterm.term_names); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 425 | } |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 426 | (void) fprintf(stderr, "and\t%s\n", qp->tterm.term_names); |
| 427 | if (!remove_collision(rp->tterm.term_names, |
| 428 | qp->tterm.term_names)) { |
| 429 | ++multiples; |
| 430 | } |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 431 | } |
| 432 | } |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 433 | } |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 434 | if (multiples > 0) { |
| 435 | DEBUG(2, (T_RETURN("false"))); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 436 | return (FALSE); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 437 | } |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 438 | |
| 439 | DEBUG(2, ("NO MULTIPLE NAME OCCURRENCES")); |
| 440 | |
| 441 | /* |
| 442 | * First resolution stage: compute link pointers corresponding to names. |
| 443 | */ |
| 444 | total_unresolved = 0; |
| 445 | _nc_curr_col = -1; |
| 446 | for_entry_list(qp) { |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 447 | for (i = 0; i < qp->nuses; i++) { |
| 448 | bool foundit; |
| 449 | char *child = _nc_first_name(qp->tterm.term_names); |
| 450 | char *lookfor = qp->uses[i].name; |
| 451 | long lookline = qp->uses[i].line; |
| 452 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 453 | if (lookfor == 0) |
| 454 | continue; |
| 455 | |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 456 | foundit = FALSE; |
| 457 | |
| 458 | _nc_set_type(child); |
| 459 | |
| 460 | /* first, try to resolve from in-core records */ |
| 461 | for_entry_list(rp) { |
| 462 | if (rp != qp |
| 463 | && _nc_name_match(rp->tterm.term_names, lookfor, "|")) { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 464 | DEBUG(2, ("%s: resolving use=%s %p (in core)", |
| 465 | child, lookfor, lookfor)); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 466 | |
| 467 | qp->uses[i].link = rp; |
| 468 | foundit = TRUE; |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 469 | |
| 470 | /* verify that there are no earlier uses */ |
| 471 | for (j = 0; j < i; ++j) { |
| 472 | if (qp->uses[j].link != NULL |
| 473 | && !strcmp(qp->uses[j].link->tterm.term_names, |
| 474 | rp->tterm.term_names)) { |
| 475 | _nc_warning("duplicate use=%s", lookfor); |
| 476 | break; |
| 477 | } |
| 478 | } |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 479 | } |
| 480 | } |
| 481 | |
| 482 | /* if that didn't work, try to merge in a compiled entry */ |
| 483 | if (!foundit) { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 484 | TERMTYPE2 thisterm; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 485 | char filename[PATH_MAX]; |
| 486 | |
| 487 | memset(&thisterm, 0, sizeof(thisterm)); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 488 | if (_nc_read_entry2(lookfor, filename, &thisterm) == 1) { |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 489 | DEBUG(2, ("%s: resolving use=%s (compiled)", |
| 490 | child, lookfor)); |
| 491 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 492 | TYPE_MALLOC(ENTRY, 1, rp); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 493 | rp->tterm = thisterm; |
| 494 | rp->nuses = 0; |
| 495 | rp->next = lastread; |
| 496 | lastread = rp; |
| 497 | |
| 498 | qp->uses[i].link = rp; |
| 499 | foundit = TRUE; |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 500 | |
| 501 | /* verify that there are no earlier uses */ |
| 502 | for (j = 0; j < i; ++j) { |
| 503 | if (qp->uses[j].link != NULL |
| 504 | && !strcmp(qp->uses[j].link->tterm.term_names, |
| 505 | rp->tterm.term_names)) { |
| 506 | _nc_warning("duplicate use=%s", lookfor); |
| 507 | break; |
| 508 | } |
| 509 | } |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 510 | } |
| 511 | } |
| 512 | |
| 513 | /* no good, mark this one unresolvable and complain */ |
| 514 | if (!foundit) { |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 515 | total_unresolved++; |
| 516 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 517 | _nc_curr_line = (int) lookline; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 518 | _nc_warning("resolution of use=%s failed", lookfor); |
| 519 | qp->uses[i].link = 0; |
| 520 | } |
| 521 | } |
| 522 | } |
| 523 | if (total_unresolved) { |
| 524 | /* free entries read in off disk */ |
| 525 | _nc_free_entries(lastread); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 526 | DEBUG(2, (T_RETURN("false"))); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 527 | return (FALSE); |
| 528 | } |
| 529 | |
| 530 | DEBUG(2, ("NAME RESOLUTION COMPLETED OK")); |
| 531 | |
| 532 | /* |
| 533 | * OK, at this point all (char *) references in `name' members |
| 534 | * have been successfully converted to (ENTRY *) pointers in |
| 535 | * `link' members. Time to do the actual merges. |
| 536 | */ |
| 537 | if (fullresolve) { |
| 538 | do { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 539 | ENTRY merged; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 540 | |
| 541 | keepgoing = FALSE; |
| 542 | |
| 543 | for_entry_list(qp) { |
| 544 | if (qp->nuses > 0) { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 545 | DEBUG(2, ("%s: attempting merge of %d entries", |
| 546 | _nc_first_name(qp->tterm.term_names), |
| 547 | qp->nuses)); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 548 | /* |
| 549 | * If any of the use entries we're looking for is |
| 550 | * incomplete, punt. We'll catch this entry on a |
| 551 | * subsequent pass. |
| 552 | */ |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 553 | for (i = 0; i < qp->nuses; i++) { |
| 554 | if (qp->uses[i].link |
| 555 | && qp->uses[i].link->nuses) { |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 556 | DEBUG(2, ("%s: use entry %d unresolved", |
| 557 | _nc_first_name(qp->tterm.term_names), i)); |
| 558 | goto incomplete; |
| 559 | } |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 560 | } |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 561 | |
| 562 | /* |
| 563 | * First, make sure there is no garbage in the |
| 564 | * merge block. As a side effect, copy into |
| 565 | * the merged entry the name field and string |
| 566 | * table pointer. |
| 567 | */ |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 568 | _nc_copy_termtype2(&(merged.tterm), &(qp->tterm)); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 569 | |
| 570 | /* |
| 571 | * Now merge in each use entry in the proper |
| 572 | * (reverse) order. |
| 573 | */ |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 574 | for (; qp->nuses; qp->nuses--) { |
| 575 | int n = (int) (qp->nuses - 1); |
| 576 | validate_merge(&merged, qp->uses[n].link); |
| 577 | _nc_merge_entry(&merged, qp->uses[n].link); |
| 578 | free(qp->uses[n].name); |
| 579 | } |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 580 | |
| 581 | /* |
| 582 | * Now merge in the original entry. |
| 583 | */ |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 584 | validate_merge(&merged, qp); |
| 585 | _nc_merge_entry(&merged, qp); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 586 | |
| 587 | /* |
| 588 | * Replace the original entry with the merged one. |
| 589 | */ |
| 590 | FreeIfNeeded(qp->tterm.Booleans); |
| 591 | FreeIfNeeded(qp->tterm.Numbers); |
| 592 | FreeIfNeeded(qp->tterm.Strings); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 593 | FreeIfNeeded(qp->tterm.str_table); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 594 | #if NCURSES_XNAMES |
| 595 | FreeIfNeeded(qp->tterm.ext_Names); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 596 | FreeIfNeeded(qp->tterm.ext_str_table); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 597 | #endif |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 598 | qp->tterm = merged.tterm; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 599 | _nc_wrap_entry(qp, TRUE); |
| 600 | |
| 601 | /* |
| 602 | * We know every entry is resolvable because name resolution |
| 603 | * didn't bomb. So go back for another pass. |
| 604 | */ |
| 605 | /* FALLTHRU */ |
| 606 | incomplete: |
| 607 | keepgoing = TRUE; |
| 608 | } |
| 609 | } |
| 610 | } while |
| 611 | (keepgoing); |
| 612 | |
| 613 | DEBUG(2, ("MERGES COMPLETED OK")); |
| 614 | } |
| 615 | |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 616 | DEBUG(2, ("RESOLUTION FINISHED")); |
| 617 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 618 | if (fullresolve) { |
| 619 | _nc_curr_col = -1; |
| 620 | for_entry_list(qp) { |
| 621 | _nc_curr_line = (int) qp->startline; |
| 622 | _nc_set_type(_nc_first_name(qp->tterm.term_names)); |
| 623 | /* |
| 624 | * tic overrides this function pointer to provide more verbose |
| 625 | * checking. |
| 626 | */ |
| 627 | if (_nc_check_termtype2 != sanity_check2) { |
| 628 | SCREEN *save_SP = SP; |
| 629 | SCREEN fake_sp; |
| 630 | TERMINAL fake_tm; |
| 631 | TERMINAL *save_tm = cur_term; |
| 632 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 633 | /* |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 634 | * Setup so that tic can use ordinary terminfo interface to |
| 635 | * obtain capability information. |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 636 | */ |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 637 | memset(&fake_sp, 0, sizeof(fake_sp)); |
| 638 | memset(&fake_tm, 0, sizeof(fake_tm)); |
| 639 | fake_sp._term = &fake_tm; |
| 640 | TerminalType(&fake_tm) = qp->tterm; |
| 641 | _nc_set_screen(&fake_sp); |
| 642 | set_curterm(&fake_tm); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 643 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 644 | _nc_check_termtype2(&qp->tterm, literal); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 645 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 646 | /* |
| 647 | * Checking calls tparm, which can allocate memory. Fix leaks. |
| 648 | */ |
| 649 | #define TPS(name) fake_tm.tparm_state.name |
| 650 | FreeAndNull(TPS(out_buff)); |
| 651 | FreeAndNull(TPS(fmt_buff)); |
| 652 | #undef TPS |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 653 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 654 | _nc_set_screen(save_SP); |
| 655 | set_curterm(save_tm); |
| 656 | } else { |
| 657 | fixup_acsc(&qp->tterm, literal); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 658 | } |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 659 | } |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 660 | DEBUG(2, ("SANITY CHECK FINISHED")); |
| 661 | } |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 662 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 663 | DEBUG(2, (T_RETURN("true"))); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 664 | return (TRUE); |
| 665 | } |
| 666 | |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 667 | /* |
| 668 | * This bit of legerdemain turns all the terminfo variable names into |
| 669 | * references to locations in the arrays Booleans, Numbers, and Strings --- |
| 670 | * precisely what's needed. |
| 671 | */ |
| 672 | |
| 673 | #undef CUR |
| 674 | #define CUR tp-> |
| 675 | |
| 676 | static void |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 677 | fixup_acsc(TERMTYPE2 *tp, int literal) |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 678 | { |
| 679 | if (!literal) { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 680 | if (acs_chars == ABSENT_STRING |
| 681 | && PRESENT(enter_alt_charset_mode) |
| 682 | && PRESENT(exit_alt_charset_mode)) |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 683 | acs_chars = strdup(VT_ACSC); |
| 684 | } |
| 685 | } |
| 686 | |
| 687 | static void |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 688 | sanity_check2(TERMTYPE2 *tp, bool literal) |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 689 | { |
| 690 | if (!PRESENT(exit_attribute_mode)) { |
| 691 | #ifdef __UNUSED__ /* this casts too wide a net */ |
| 692 | bool terminal_entry = !strchr(tp->term_names, '+'); |
| 693 | if (terminal_entry && |
| 694 | (PRESENT(set_attributes) |
| 695 | || PRESENT(enter_standout_mode) |
| 696 | || PRESENT(enter_underline_mode) |
| 697 | || PRESENT(enter_blink_mode) |
| 698 | || PRESENT(enter_bold_mode) |
| 699 | || PRESENT(enter_dim_mode) |
| 700 | || PRESENT(enter_secure_mode) |
| 701 | || PRESENT(enter_protected_mode) |
| 702 | || PRESENT(enter_reverse_mode))) |
| 703 | _nc_warning("no exit_attribute_mode"); |
| 704 | #endif /* __UNUSED__ */ |
| 705 | PAIRED(enter_standout_mode, exit_standout_mode); |
| 706 | PAIRED(enter_underline_mode, exit_underline_mode); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 707 | #if defined(enter_italics_mode) && defined(exit_italics_mode) |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 708 | PAIRED(enter_italics_mode, exit_italics_mode); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 709 | #endif |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 710 | } |
| 711 | |
| 712 | /* we do this check/fix in postprocess_termcap(), but some packagers |
| 713 | * prefer to bypass it... |
| 714 | */ |
| 715 | if (!literal) { |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 716 | fixup_acsc(tp, literal); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 717 | ANDMISSING(enter_alt_charset_mode, acs_chars); |
| 718 | ANDMISSING(exit_alt_charset_mode, acs_chars); |
| 719 | } |
| 720 | |
| 721 | /* listed in structure-member order of first argument */ |
| 722 | PAIRED(enter_alt_charset_mode, exit_alt_charset_mode); |
| 723 | ANDMISSING(enter_blink_mode, exit_attribute_mode); |
| 724 | ANDMISSING(enter_bold_mode, exit_attribute_mode); |
| 725 | PAIRED(exit_ca_mode, enter_ca_mode); |
| 726 | PAIRED(enter_delete_mode, exit_delete_mode); |
| 727 | ANDMISSING(enter_dim_mode, exit_attribute_mode); |
| 728 | PAIRED(enter_insert_mode, exit_insert_mode); |
| 729 | ANDMISSING(enter_secure_mode, exit_attribute_mode); |
| 730 | ANDMISSING(enter_protected_mode, exit_attribute_mode); |
| 731 | ANDMISSING(enter_reverse_mode, exit_attribute_mode); |
| 732 | PAIRED(from_status_line, to_status_line); |
| 733 | PAIRED(meta_off, meta_on); |
| 734 | |
| 735 | PAIRED(prtr_on, prtr_off); |
| 736 | PAIRED(save_cursor, restore_cursor); |
| 737 | PAIRED(enter_xon_mode, exit_xon_mode); |
| 738 | PAIRED(enter_am_mode, exit_am_mode); |
| 739 | ANDMISSING(label_off, label_on); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 740 | #if defined(display_clock) && defined(remove_clock) |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 741 | PAIRED(display_clock, remove_clock); |
| 742 | #endif |
| 743 | ANDMISSING(set_color_pair, initialize_pair); |
| 744 | } |
| 745 | |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 746 | #if NO_LEAKS |
| 747 | NCURSES_EXPORT(void) |
| 748 | _nc_leaks_tic(void) |
| 749 | { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 750 | T((T_CALLED("_nc_leaks_tic()"))); |
| 751 | _nc_globals.leak_checking = TRUE; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 752 | _nc_alloc_entry_leaks(); |
| 753 | _nc_captoinfo_leaks(); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 754 | _nc_comp_scan_leaks(); |
| 755 | #if BROKEN_LINKER || USE_REENTRANT |
| 756 | _nc_names_leaks(); |
| 757 | _nc_codes_leaks(); |
| 758 | #endif |
| 759 | _nc_tic_expand(0, FALSE, 0); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 760 | T((T_RETURN(""))); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 761 | } |
| 762 | |
| 763 | NCURSES_EXPORT(void) |
| 764 | _nc_free_tic(int code) |
| 765 | { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 766 | T((T_CALLED("_nc_free_tic(%d)"), code)); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 767 | _nc_leaks_tic(); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 768 | exit_terminfo(code); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 769 | } |
| 770 | #endif |